i2c: aspeed: Add tests related to bus recovery i2c-aspeed-test.c
- aspeed_i2c_master_xfer_test_idle_bus tests the condition when the bus is idle and no recovery needs to be performed.
- aspeed_i2c_master_xfer_test_recover_bus_reset tests the condition when the bus is not idle but there is no bus error and hence the bus is reset before the transaction.
- aspeed_i2c_master_xfer_test_recover_bus_error tests a condition when there is a bus error.
Change-Id: I76449f6050dd4e26d0a846b9c4121386adeacd7a
Google-Bug-Id: 113188254
Signed-off-by: Harshal Tushar Lehri <halehri@google.com>
diff --git a/drivers/i2c/busses/i2c-aspeed-test.c b/drivers/i2c/busses/i2c-aspeed-test.c
index f7f2e6d..28fa60c 100644
--- a/drivers/i2c/busses/i2c-aspeed-test.c
+++ b/drivers/i2c/busses/i2c-aspeed-test.c
@@ -64,21 +64,22 @@
return ctx;
}
-static void aspeed_i2c_master_xfer_test_basic(struct test *test)
+/* Adds expectations which are common to many test cases which test conditions
+ * that eventually lead to a transfer (e.g after performing some recovery steps etc).
+ */
+static void aspeed_i2c_master_xfer_start_transaction(struct test *test,
+ struct mock_expectation *precondition)
{
struct aspeed_i2c_test *ctx = test->priv;
struct i2c_client *client = ctx->client;
- struct mock_expectation *read_cmd_reg, *write_client_addr,
+ struct mock_expectation *write_client_addr,
*write_start_cmd, *slave_response, *ack_slave_response,
*write_first_byte, *first_byte_tx_cmd, *first_byte_sent,
*ack_first_byte_tx, *write_second_byte, *second_byte_tx_cmd,
*second_byte_sent, *ack_second_byte_tx, *stop_tx, *bus_stopped,
*write_bus_stopped;
- u8 msg[] = {0xae, 0x00};
- read_cmd_reg = Returns(EXPECT_CALL(readl(u32_eq(test,
- ASPEED_I2C_CMD_REG))),
- u32_return(test, !ASPEED_I2CD_BUS_BUSY_STS));
+ u8 msg[] = {0xae, 0x00};
/* Start transaction. */
write_client_addr = EXPECT_CALL(writel(
@@ -165,7 +166,7 @@
writel(u32_eq(test, ASPEED_I2CD_INTR_NORMAL_STOP),
u32_eq(test, ASPEED_I2C_INTR_STS_REG)));
- InSequence(test, read_cmd_reg, write_client_addr, write_start_cmd,
+ InSequence(test, precondition, write_client_addr, write_start_cmd,
slave_response, ack_slave_response, write_first_byte,
first_byte_tx_cmd, first_byte_sent, ack_first_byte_tx,
write_second_byte, second_byte_tx_cmd, second_byte_sent,
@@ -176,6 +177,163 @@
i2c_master_send(client, msg, ARRAY_SIZE(msg)));
}
+static void aspeed_i2c_master_xfer_test_basic(struct test *test)
+{
+ struct mock_expectation *read_cmd_reg;
+
+ /* Set expectation to return a value indicating the bus is not busy */
+ read_cmd_reg = Returns(EXPECT_CALL(readl(u32_eq(test,
+ ASPEED_I2C_CMD_REG))),
+ u32_return(test, !ASPEED_I2CD_BUS_BUSY_STS));
+
+ aspeed_i2c_master_xfer_start_transaction(test, /*precondition=*/read_cmd_reg);
+}
+
+static void aspeed_i2c_master_xfer_test_idle_bus(struct test *test)
+{
+ struct mock_expectation *read_cmd_reg_bus_busy, *read_cmd_reg_bus_recovery;
+
+ read_cmd_reg_bus_busy = Returns(EXPECT_CALL(readl(u32_eq(test,
+ ASPEED_I2C_CMD_REG))),
+ u32_return(test, ASPEED_I2CD_BUS_BUSY_STS));
+ /* Read command registers which has both the SDA_LINE_STS and
+ * SCL_LINE_STS bits set, meaning the bus is idle and no recovery
+ * is not necessary */
+ read_cmd_reg_bus_recovery = Returns(EXPECT_CALL(readl(u32_eq(test,
+ ASPEED_I2C_CMD_REG))),
+ u32_return(test, ASPEED_I2CD_SDA_LINE_STS | ASPEED_I2CD_SCL_LINE_STS));
+
+ InSequence(test, read_cmd_reg_bus_busy, read_cmd_reg_bus_recovery);
+
+ aspeed_i2c_master_xfer_start_transaction(test, /*precondition=*/read_cmd_reg_bus_busy);
+}
+
+static void aspeed_i2c_master_xfer_test_recover_bus_reset(struct test *test)
+{
+ /* Expectation set during the recovery phase. */
+ struct mock_expectation *read_cmd_reg_bus_busy, *read_cmd_reg_sda_line_set,
+ *write_stop_cmd, *disable_intr, *ack_all_intr, *disable_aspeed,
+ *read_clk_reg_value, *write_clk_reg_value, *write_no_timeout_ctrl,
+ *read_func_ctrl_reg, *enable_master_mode, *enable_interrupts;
+
+ /* Read command register and return state that indicates the bus to be busy */
+ read_cmd_reg_bus_busy = Returns(EXPECT_CALL(readl(u32_eq(test,
+ ASPEED_I2C_CMD_REG))),
+ u32_return(test, ASPEED_I2CD_BUS_BUSY_STS));
+ /* Read command register and only set the SDA_LINE to trigger bus recovery */
+ read_cmd_reg_sda_line_set = Returns(EXPECT_CALL(readl(u32_eq(test,
+ ASPEED_I2C_CMD_REG))),
+ u32_return(test, ASPEED_I2CD_SDA_LINE_STS));
+ /* Stop the bus */
+ write_stop_cmd = EXPECT_CALL(writel(u32_eq(test, ASPEED_I2CD_M_STOP_CMD),
+ u32_eq(test, ASPEED_I2C_CMD_REG)));
+
+ /* Disable all interrupts */
+ disable_intr = EXPECT_CALL(writel(u32_eq(test, 0),
+ u32_eq(test, ASPEED_I2C_INTR_CTRL_REG)));
+
+ /* Ack all interrupts */
+ ack_all_intr = EXPECT_CALL(writel(u32_eq(test, 0xffffffff),
+ u32_eq(test, ASPEED_I2C_INTR_STS_REG)));
+
+ /* Disable everything */
+ disable_aspeed = EXPECT_CALL(writel(u32_eq(test, 0),
+ u32_eq(test, ASPEED_I2C_FUN_CTRL_REG)));
+
+ /* Read Timing Register and initialize the aspeed clock */
+ /* TODO(halehri): Maybe test this with better values */
+ read_clk_reg_value = Returns(EXPECT_CALL(readl(u32_eq(test, ASPEED_I2C_AC_TIMING_REG1))),
+ u32_return(test, 0));
+
+ write_clk_reg_value = EXPECT_CALL(writel(u32_eq(test, 0),
+ u32_eq(test, ASPEED_I2C_AC_TIMING_REG1)));
+
+ write_no_timeout_ctrl = EXPECT_CALL(writel(u32_eq(test, ASPEED_NO_TIMEOUT_CTRL),
+ u32_eq(test, ASPEED_I2C_AC_TIMING_REG2)));
+
+ /* Enable Master mode */
+ read_func_ctrl_reg = Returns(EXPECT_CALL(readl(u32_eq(test, ASPEED_I2C_FUN_CTRL_REG))),
+ u32_return(test, 0));
+
+ enable_master_mode = EXPECT_CALL(writel(u32_eq(test, ASPEED_I2CD_MASTER_EN | ASPEED_I2CD_MULTI_MASTER_DIS),
+ u32_eq(test, ASPEED_I2C_FUN_CTRL_REG)));
+
+ /* Enable interrupts again */
+ enable_interrupts = EXPECT_CALL(writel(u32_eq(test, ASPEED_I2CD_INTR_ALL),
+ u32_eq(test, ASPEED_I2C_INTR_CTRL_REG)));
+
+ InSequence(test, read_cmd_reg_bus_busy, read_cmd_reg_sda_line_set,
+ write_stop_cmd, disable_intr, ack_all_intr, disable_aspeed,
+ read_clk_reg_value, write_clk_reg_value, write_no_timeout_ctrl,
+ read_func_ctrl_reg, enable_master_mode, enable_interrupts);
+
+ aspeed_i2c_master_xfer_start_transaction(test, /*precondition=*/enable_interrupts);
+}
+
+static void aspeed_i2c_master_xfer_test_recover_bus_error(struct test *test) {
+ /* Expectation set during the recovery phase. */
+ struct mock_expectation *read_cmd_reg_bus_busy, *read_cmd_reg_sda_hung,
+ *write_bus_recovery_cmd, *disable_intr, *ack_all_intr, *disable_aspeed,
+ *read_clk_reg_value, *write_clk_reg_value, *write_no_timeout_ctrl,
+ *read_func_ctrl_reg, *enable_master_mode, *enable_interrupts;
+
+ /* Read command register and return state that indicates the bus to be busy */
+ read_cmd_reg_bus_busy = Returns(EXPECT_CALL(readl(u32_eq(test,
+ ASPEED_I2C_CMD_REG))),
+ u32_return(test, ASPEED_I2CD_BUS_BUSY_STS));
+ /* Read command register and return value that triggers a bus error (SDA hung) */
+ read_cmd_reg_sda_hung = Returns(EXPECT_CALL(readl(u32_eq(test,
+ ASPEED_I2C_CMD_REG))),
+ u32_return(test, 0));
+ /* This is the only difference between the previous test case and this one.
+ * The Bus is not stopped and Bus Recovery Command gets written to
+ * the command register.
+ */
+ write_bus_recovery_cmd = EXPECT_CALL(writel(u32_eq(test, ASPEED_I2CD_BUS_RECOVER_CMD),
+ u32_eq(test, ASPEED_I2C_CMD_REG)));
+
+ /* Disable all interrupts */
+ disable_intr = EXPECT_CALL(writel(u32_eq(test, 0),
+ u32_eq(test, ASPEED_I2C_INTR_CTRL_REG)));
+
+ /* Ack all interrupts */
+ ack_all_intr = EXPECT_CALL(writel(u32_eq(test, 0xffffffff),
+ u32_eq(test, ASPEED_I2C_INTR_STS_REG)));
+
+ /* Disable everything */
+ disable_aspeed = EXPECT_CALL(writel(u32_eq(test, 0),
+ u32_eq(test, ASPEED_I2C_FUN_CTRL_REG)));
+
+ /* Read Timing Register and initialize the aspeed clock */
+ /* TODO(halehri): Maybe test this with better values */
+ read_clk_reg_value = Returns(EXPECT_CALL(readl(u32_eq(test, ASPEED_I2C_AC_TIMING_REG1))),
+ u32_return(test, 0));
+
+ write_clk_reg_value = EXPECT_CALL(writel(u32_eq(test, 0),
+ u32_eq(test, ASPEED_I2C_AC_TIMING_REG1)));
+
+ write_no_timeout_ctrl = EXPECT_CALL(writel(u32_eq(test, ASPEED_NO_TIMEOUT_CTRL),
+ u32_eq(test, ASPEED_I2C_AC_TIMING_REG2)));
+
+ /* Enable Master mode */
+ read_func_ctrl_reg = Returns(EXPECT_CALL(readl(u32_eq(test, ASPEED_I2C_FUN_CTRL_REG))),
+ u32_return(test, 0));
+
+ enable_master_mode = EXPECT_CALL(writel(u32_eq(test, ASPEED_I2CD_MASTER_EN | ASPEED_I2CD_MULTI_MASTER_DIS),
+ u32_eq(test, ASPEED_I2C_FUN_CTRL_REG)));
+
+ /* Enable interrupts again */
+ enable_interrupts = EXPECT_CALL(writel(u32_eq(test, ASPEED_I2CD_INTR_ALL),
+ u32_eq(test, ASPEED_I2C_INTR_CTRL_REG)));
+
+ InSequence(test, read_cmd_reg_bus_busy, read_cmd_reg_sda_hung,
+ write_bus_recovery_cmd, disable_intr, ack_all_intr, disable_aspeed,
+ read_clk_reg_value, write_clk_reg_value, write_no_timeout_ctrl,
+ read_func_ctrl_reg, enable_master_mode, enable_interrupts);
+
+ aspeed_i2c_master_xfer_start_transaction(test, /*precondition=*/enable_interrupts);
+}
+
static u32 aspeed_i2c_get_base_clk(u32 reg_val)
{
return reg_val & ASPEED_I2CD_TIME_BASE_DIVISOR_MASK;
@@ -371,7 +529,6 @@
struct mock_param_capturer *adap_capturer,
*irq_capturer,
*irq_ctx_capturer;
- struct mock_expectation *handle;
struct aspeed_i2c_test *ctx;
mock_set_default_action(mock_get_global_mock(),
@@ -384,9 +541,8 @@
int_return(test, 0));
/* TODO(brendanhiggins@google.com): Fix this so mock_validate works. */
- handle = RetireOnSaturation(Returns(EXPECT_CALL(readl(any(test))),
- u32_return(test, 0)));
- handle->max_calls_expected = 2;
+ Between(1, 2, RetireOnSaturation(Returns(EXPECT_CALL(readl(any(test))),
+ u32_return(test, 0))));
RetireOnSaturation(EXPECT_CALL(
writel(u32_eq(test, 0),
u32_eq(test, ASPEED_I2C_INTR_CTRL_REG))));
@@ -474,7 +630,10 @@
}
static struct test_case aspeed_i2c_test_cases[] = {
- TEST_CASE(aspeed_i2c_master_xfer_test_basic),
+ TEST_CASE(aspeed_i2c_master_xfer_test_basic),
+ TEST_CASE(aspeed_i2c_master_xfer_test_idle_bus),
+ TEST_CASE(aspeed_i2c_master_xfer_test_recover_bus_reset),
+ TEST_CASE(aspeed_i2c_master_xfer_test_recover_bus_error),
TEST_CASE(aspeed_i2c_24xx_get_clk_reg_val_test_min),
TEST_CASE(aspeed_i2c_24xx_get_clk_reg_val_test_max),
TEST_CASE(aspeed_i2c_24xx_get_clk_reg_val_test_datasheet),