From b2bf76967bf2a96294aad933449bc0b3bfd12cce Mon Sep 17 00:00:00 2001 From: Tomasz Michalec Date: Thu, 10 Mar 2022 13:07:21 +0100 Subject: zephyr: emul: Fix sending Hard and Cable reset in TCPCI emulator Transmitting Hard or Cable reset should alywas set TransmitSOP*MessageSuccessful and TransmitSOP*MessageFailed bits in ALERT register. Now partner emulators aren't reporting message status using tcpci_emul_partner_msg_status() when receive Hard or Cable reset. Instead TCPCI emulator transmit handler set correct ALERT state. Additionally transmitting Hard Reset sets RECEIVE_DETECT register to 0, clears receive buffer and resets mask registers. BUG=b:223766685 BRANCH=none TEST=zmake configure --test test-drivers Signed-off-by: Tomasz Michalec Change-Id: I686e4001b65cc05621563861903c76e620224e3e Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3515940 Tested-by: Tomasz Michalec Reviewed-by: Denis Brockus Commit-Queue: Tomasz Michalec --- zephyr/emul/tcpc/emul_tcpci.c | 109 ++++++++++++++++++++------- zephyr/emul/tcpc/emul_tcpci_partner_common.c | 9 ++- zephyr/include/emul/tcpc/emul_tcpci.h | 3 +- 3 files changed, 90 insertions(+), 31 deletions(-) diff --git a/zephyr/emul/tcpc/emul_tcpci.c b/zephyr/emul/tcpc/emul_tcpci.c index 61f9cc7f0d..c16e99d4c4 100644 --- a/zephyr/emul/tcpc/emul_tcpci.c +++ b/zephyr/emul/tcpc/emul_tcpci.c @@ -524,6 +524,10 @@ void tcpci_emul_partner_msg_status(const struct emul *emul, case TCPCI_EMUL_TX_FAILED: tx_status_alert = TCPC_REG_ALERT_TX_FAILED; break; + case TCPCI_EMUL_TX_CABLE_HARD_RESET: + tx_status_alert = TCPC_REG_ALERT_TX_SUCCESS | + TCPC_REG_ALERT_TX_FAILED; + break; default: __ASSERT(0, "Invalid partner TX status 0x%x", status); return; @@ -637,6 +641,23 @@ static void tcpci_emul_reset_role_ctrl(const struct emul *emul) } } +/** + * @brief Reset mask registers that are reset upon receiving or transmitting + * Hard Reset message. + * + * @param emul Pointer to TCPCI emulator + */ +static void tcpci_emul_reset_mask_regs(const struct emul *emul) +{ + struct tcpci_emul_data *data = emul->data; + + data->reg[TCPC_REG_ALERT_MASK] = 0xff; + data->reg[TCPC_REG_ALERT_MASK + 1] = 0x7f; + data->reg[TCPC_REG_POWER_STATUS_MASK] = 0xff; + data->reg[TCPC_REG_EXT_STATUS_MASK] = 0x01; + data->reg[TCPC_REG_ALERT_EXTENDED_MASK] = 0x07; +} + /** * @brief Reset registers to default values. Vendor and reserved registers * are not changed. @@ -650,12 +671,7 @@ static int tcpci_emul_reset(const struct emul *emul) data->reg[TCPC_REG_ALERT] = 0x00; data->reg[TCPC_REG_ALERT + 1] = 0x00; - data->reg[TCPC_REG_ALERT_MASK] = 0xff; - data->reg[TCPC_REG_ALERT_MASK + 1] = 0x7f; - data->reg[TCPC_REG_POWER_STATUS_MASK] = 0xff; data->reg[TCPC_REG_FAULT_STATUS_MASK] = 0xff; - data->reg[TCPC_REG_EXT_STATUS_MASK] = 0x01; - data->reg[TCPC_REG_ALERT_EXTENDED_MASK] = 0x07; data->reg[TCPC_REG_CONFIG_STD_OUTPUT] = 0x60; data->reg[TCPC_REG_TCPC_CTRL] = 0x00; data->reg[TCPC_REG_FAULT_CTRL] = 0x00; @@ -683,6 +699,7 @@ static int tcpci_emul_reset(const struct emul *emul) data->reg[TCPC_REG_VBUS_NONDEFAULT_TARGET] = 0x00; data->reg[TCPC_REG_VBUS_NONDEFAULT_TARGET + 1] = 0x00; + tcpci_emul_reset_mask_regs(emul); tcpci_emul_reset_role_ctrl(emul); if (data->dev_ops && data->dev_ops->reset) { @@ -1096,30 +1113,6 @@ static int tcpci_emul_handle_command(const struct emul *emul) return 0; } -/** - * @brief Handle write to transmit register - * - * @param emul Pointer to TCPCI emulator - * - * @return 0 on success - */ -static int tcpci_emul_handle_transmit(const struct emul *emul) -{ - struct tcpci_emul_data *data = emul->data; - - data->tx_msg->cnt = data->tx_msg->idx; - data->tx_msg->type = TCPC_REG_TRANSMIT_TYPE(data->write_data); - data->tx_msg->idx = 0; - - if (data->partner && data->partner->transmit) { - data->partner->transmit(emul, data->partner, data->tx_msg, - TCPC_REG_TRANSMIT_TYPE(data->write_data), - TCPC_REG_TRANSMIT_RETRY(data->write_data)); - } - - return 0; -} - /** * @brief Load next rx message and inform partner which message was consumed * by TCPC @@ -1156,6 +1149,64 @@ static int tcpci_emul_get_next_rx_msg(const struct emul *emul) return 0; } +/** + * @brief Perform actions that are expected by TCPC on disabling PD message + * delivery (clear RECEIVE_DETECT register, clear already received + * messages in buffer and reset mask registers) + * + * @param emul Pointer to TCPCI emulator + */ +static void tcpci_emul_disable_pd_msg_delivery(const struct emul *emul) +{ + tcpci_emul_set_reg(emul, TCPC_REG_RX_DETECT, 0); + /* Clear received messages */ + while (tcpci_emul_get_next_rx_msg(emul)) + ; + tcpci_emul_reset_mask_regs(emul); +} + +/** + * @brief Handle write to transmit register + * + * @param emul Pointer to TCPCI emulator + * + * @return 0 on success + */ +static int tcpci_emul_handle_transmit(const struct emul *emul) +{ + struct tcpci_emul_data *data = emul->data; + enum tcpci_msg_type type; + + data->tx_msg->cnt = data->tx_msg->idx; + data->tx_msg->type = TCPC_REG_TRANSMIT_TYPE(data->write_data); + data->tx_msg->idx = 0; + + type = TCPC_REG_TRANSMIT_TYPE(data->write_data); + + if (data->partner && data->partner->transmit) { + data->partner->transmit(emul, data->partner, data->tx_msg, type, + TCPC_REG_TRANSMIT_RETRY(data->write_data)); + } + + switch (type) { + case TCPCI_MSG_TX_HARD_RESET: + tcpci_emul_disable_pd_msg_delivery(emul); + /* fallthrough */ + case TCPCI_MSG_CABLE_RESET: + /* + * Cable and Hard reset are special and set success and fail + * in Alert reg regardless of the outcome of the transmission + */ + tcpci_emul_partner_msg_status(emul, + TCPCI_EMUL_TX_CABLE_HARD_RESET); + break; + default: + break; + } + + return 0; +} + /** * @brief Handle I2C write message. It is checked if accessed register isn't RO * and reserved bits are set to 0. diff --git a/zephyr/emul/tcpc/emul_tcpci_partner_common.c b/zephyr/emul/tcpc/emul_tcpci_partner_common.c index e3805c1cd2..affde1225f 100644 --- a/zephyr/emul/tcpc/emul_tcpci_partner_common.c +++ b/zephyr/emul/tcpc/emul_tcpci_partner_common.c @@ -440,7 +440,14 @@ enum tcpci_partner_handler_res tcpci_partner_common_msg_handler( tcpci_partner_log_msg(data, tx_msg, TCPCI_PARTNER_SENDER_TCPM, tx_status); - tcpci_emul_partner_msg_status(data->tcpci_emul, tx_status); + /* + * Do not change alert register in TCPCI emulator upon receiving + * hard reset or cable reset + */ + if (type != TCPCI_MSG_TX_HARD_RESET && type != TCPCI_MSG_CABLE_RESET) { + tcpci_emul_partner_msg_status(data->tcpci_emul, tx_status); + } + /* If receiving message was unsuccessful, abandon processing message */ if (tx_status != TCPCI_EMUL_TX_SUCCESS) { return TCPCI_PARTNER_COMMON_MSG_NOT_HANDLED; diff --git a/zephyr/include/emul/tcpc/emul_tcpci.h b/zephyr/include/emul/tcpc/emul_tcpci.h index 3a50481054..41e15203c7 100644 --- a/zephyr/include/emul/tcpc/emul_tcpci.h +++ b/zephyr/include/emul/tcpc/emul_tcpci.h @@ -81,7 +81,8 @@ enum tcpci_emul_rev { enum tcpci_emul_tx_status { TCPCI_EMUL_TX_SUCCESS, TCPCI_EMUL_TX_DISCARDED, - TCPCI_EMUL_TX_FAILED + TCPCI_EMUL_TX_FAILED, + TCPCI_EMUL_TX_CABLE_HARD_RESET }; /** TCPCI specific device operations. Not all of them need to be implemented. */ -- cgit v1.2.1