summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomasz Michalec <tm@semihalf.com>2021-12-28 17:08:51 +0100
committerCommit Bot <commit-bot@chromium.org>2022-01-14 23:07:31 +0000
commit0c279f0c9e64b4d90c8eb3079d2d6ab8e18dfa94 (patch)
tree3a0088ad220f9f5e996c2ed724d93ac403bd03a3
parent6d4f386d19670dffc15b6d145e1f475d1ce6dc80 (diff)
downloadchrome-ec-0c279f0c9e64b4d90c8eb3079d2d6ab8e18dfa94.tar.gz
zephyr: drivers: Add DRP TCPCI partner
Add dual role TCPCI partner emulator which can be attached to TCPCI emulator as sink or source. DRP emulator use sink and source partner emulators as components. BUG=none BRANCH=none TEST=make configure --test zephyr/test/drivers Signed-off-by: Tomasz Michalec <tm@semihalf.com> Change-Id: I83951c8daa14ce3129a7ab344523b1664b380322 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3358579 Reviewed-by: Denis Brockus <dbrockus@chromium.org> Tested-by: Tomasz Michalec <tmichalec@google.com> Commit-Queue: Tomasz Michalec <tmichalec@google.com>
-rw-r--r--zephyr/emul/tcpc/CMakeLists.txt5
-rw-r--r--zephyr/emul/tcpc/Kconfig12
-rw-r--r--zephyr/emul/tcpc/emul_tcpci_partner_drp.c262
-rw-r--r--zephyr/include/emul/tcpc/emul_tcpci_partner_drp.h109
4 files changed, 385 insertions, 3 deletions
diff --git a/zephyr/emul/tcpc/CMakeLists.txt b/zephyr/emul/tcpc/CMakeLists.txt
index ba00d766e2..19c845cb19 100644
--- a/zephyr/emul/tcpc/CMakeLists.txt
+++ b/zephyr/emul/tcpc/CMakeLists.txt
@@ -2,8 +2,9 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-zephyr_library_sources_ifdef(CONFIG_EMUL_TCPCI emul_tcpci.c)
zephyr_library_sources_ifdef(CONFIG_EMUL_PS8XXX emul_ps8xxx.c)
-zephyr_library_sources_ifdef(CONFIG_EMUL_TCPCI_PARTNER_SRC emul_tcpci_partner_src.c)
+zephyr_library_sources_ifdef(CONFIG_EMUL_TCPCI emul_tcpci.c)
zephyr_library_sources_ifdef(CONFIG_EMUL_TCPCI_PARTNER_COMMON emul_tcpci_partner_common.c)
+zephyr_library_sources_ifdef(CONFIG_EMUL_TCPCI_PARTNER_DRP emul_tcpci_partner_drp.c)
zephyr_library_sources_ifdef(CONFIG_EMUL_TCPCI_PARTNER_SNK emul_tcpci_partner_snk.c)
+zephyr_library_sources_ifdef(CONFIG_EMUL_TCPCI_PARTNER_SRC emul_tcpci_partner_src.c)
diff --git a/zephyr/emul/tcpc/Kconfig b/zephyr/emul/tcpc/Kconfig
index 424773be3f..1853ca1ae7 100644
--- a/zephyr/emul/tcpc/Kconfig
+++ b/zephyr/emul/tcpc/Kconfig
@@ -50,7 +50,17 @@ config EMUL_TCPCI_PARTNER_SNK
select EMUL_TCPCI_PARTNER_COMMON
help
Enable USB-C sink device emulator which may be attached to TCPCI
- emulator. API of source device emulator is available in
+ emulator. API of sink device emulator is available in
zephyr/include/emul/tcpc/emul_tcpci_partner_snk.h
+config EMUL_TCPCI_PARTNER_DRP
+ bool "USB-C dual role device emulator"
+ select EMUL_TCPCI_PARTNER_COMMON
+ select EMUL_TCPCI_PARTNER_SNK
+ select EMUL_TCPCI_PARTNER_SRC
+ help
+ Enable USB-C dual role device emulator which may be attached to TCPCI
+ emulator. API of dual role device emulator is available in
+ zephyr/include/emul/tcpc/emul_tcpci_partner_drp.h
+
endif # EMUL_TCPCI
diff --git a/zephyr/emul/tcpc/emul_tcpci_partner_drp.c b/zephyr/emul/tcpc/emul_tcpci_partner_drp.c
new file mode 100644
index 0000000000..bf6ee7c33a
--- /dev/null
+++ b/zephyr/emul/tcpc/emul_tcpci_partner_drp.c
@@ -0,0 +1,262 @@
+/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <logging/log.h>
+LOG_MODULE_REGISTER(tcpci_drp_emul, CONFIG_TCPCI_EMUL_LOG_LEVEL);
+
+#include <sys/byteorder.h>
+#include <zephyr.h>
+
+#include "common.h"
+#include "emul/tcpc/emul_tcpci.h"
+#include "emul/tcpc/emul_tcpci_partner_common.h"
+#include "emul/tcpc/emul_tcpci_partner_drp.h"
+#include "emul/tcpc/emul_tcpci_partner_snk.h"
+#include "emul/tcpc/emul_tcpci_partner_src.h"
+#include "tcpm/tcpci.h"
+#include "usb_pd.h"
+
+/** Check description in emul_tcpci_partner_drp.h */
+enum tcpci_partner_handler_res tcpci_drp_emul_handle_sop_msg(
+ struct tcpci_drp_emul_data *data,
+ struct tcpci_src_emul_data *src_data,
+ struct tcpci_snk_emul_data *snk_data,
+ struct tcpci_partner_data *common_data,
+ const struct tcpci_emul_partner_ops *ops,
+ const struct tcpci_emul_msg *msg)
+{
+ uint16_t pwr_status;
+ uint16_t header;
+
+ header = sys_get_le16(msg->buf);
+
+ if (PD_HEADER_CNT(header)) {
+ /* Handle data message */
+ switch (PD_HEADER_TYPE(header)) {
+ case PD_DATA_REQUEST:
+ if (data->sink) {
+ /* As sink we shouldn't accept request */
+ tcpci_partner_send_control_msg(common_data,
+ PD_CTRL_REJECT,
+ 0);
+ return TCPCI_PARTNER_COMMON_MSG_HANDLED;
+ }
+ /* As source, let source handler to handle this */
+ return TCPCI_PARTNER_COMMON_MSG_NOT_HANDLED;
+ case PD_DATA_SOURCE_CAP:
+ if (!data->sink) {
+ /* As source we shouldn't respond */
+ return TCPCI_PARTNER_COMMON_MSG_HANDLED;
+ }
+ /* As sink, let sink handler to handle this */
+ return TCPCI_PARTNER_COMMON_MSG_NOT_HANDLED;
+ }
+ } else {
+ /* Handle control message */
+ switch (PD_HEADER_TYPE(header)) {
+ case PD_CTRL_PR_SWAP:
+ tcpci_partner_send_control_msg(common_data,
+ PD_CTRL_ACCEPT,
+ 0);
+ data->in_pwr_swap = true;
+ return TCPCI_PARTNER_COMMON_MSG_HANDLED;
+ case PD_CTRL_PS_RDY:
+ if (!data->in_pwr_swap) {
+ return TCPCI_PARTNER_COMMON_MSG_NOT_HANDLED;
+ }
+ data->in_pwr_swap = false;
+
+ /* Reset counters */
+ common_data->msg_id = 0;
+ common_data->recv_msg_id = -1;
+
+ /* Perform power role swap */
+ if (!data->sink) {
+ /* Disable VBUS if emulator was source */
+ tcpci_emul_get_reg(common_data->tcpci_emul,
+ TCPC_REG_POWER_STATUS,
+ &pwr_status);
+ pwr_status &= ~TCPC_REG_POWER_STATUS_VBUS_PRES;
+ tcpci_emul_set_reg(common_data->tcpci_emul,
+ TCPC_REG_POWER_STATUS,
+ pwr_status);
+ /* Reconnect as sink */
+ data->sink = true;
+ common_data->power_role = PD_ROLE_SINK;
+ } else {
+ /* Reconnect as source */
+ data->sink = false;
+ common_data->power_role = PD_ROLE_SOURCE;
+ }
+ tcpci_partner_send_control_msg(common_data,
+ PD_CTRL_PS_RDY, 0);
+ /* Reconnect to TCPCI emulator */
+ tcpci_drp_emul_connect_to_tcpci(
+ data, src_data, snk_data, common_data,
+ ops, common_data->tcpci_emul);
+
+ return TCPCI_PARTNER_COMMON_MSG_HANDLED;
+ }
+ }
+
+ return TCPCI_PARTNER_COMMON_MSG_NOT_HANDLED;
+}
+
+/**
+ * @brief Function called when TCPM wants to transmit message. Accept received
+ * message and generate response.
+ *
+ * @param emul Pointer to TCPCI emulator
+ * @param ops Pointer to partner operations structure
+ * @param tx_msg Pointer to TX message buffer
+ * @param type Type of message
+ * @param retry Count of retries
+ */
+static void tcpci_drp_emul_transmit_op(const struct emul *emul,
+ const struct tcpci_emul_partner_ops *ops,
+ const struct tcpci_emul_msg *tx_msg,
+ enum tcpci_msg_type type,
+ int retry)
+{
+ struct tcpci_drp_emul *drp_emul =
+ CONTAINER_OF(ops, struct tcpci_drp_emul, ops);
+ enum tcpci_partner_handler_res processed;
+ uint16_t header;
+
+ header = sys_get_le16(tx_msg->buf);
+
+ /* Call common handler */
+ processed = tcpci_partner_common_msg_handler(&drp_emul->common_data,
+ tx_msg, type,
+ TCPCI_EMUL_TX_SUCCESS);
+ switch (processed) {
+ case TCPCI_PARTNER_COMMON_MSG_HARD_RESET:
+ /* Handle hard reset */
+ if (!drp_emul->data.sink) {
+ /* As source, advertise capabilities after 15 ms */
+ tcpci_src_emul_send_capability_msg(
+ &drp_emul->src_data,
+ &drp_emul->common_data,
+ 15);
+ }
+ drp_emul->snk_data.wait_for_ps_rdy = false;
+ drp_emul->snk_data.pd_completed = false;
+ return;
+ case TCPCI_PARTNER_COMMON_MSG_HANDLED:
+ if (!drp_emul->data.sink && PD_HEADER_CNT(header) == 0 &&
+ PD_HEADER_TYPE(header) == PD_CTRL_SOFT_RESET) {
+ /*
+ * As source, advertise capabilities after 15 ms after
+ * soft reset
+ */
+ tcpci_src_emul_send_capability_msg(
+ &drp_emul->src_data,
+ &drp_emul->common_data,
+ 15);
+ }
+ /* Message handled nothing to do */
+ return;
+ case TCPCI_PARTNER_COMMON_MSG_NOT_HANDLED:
+ default:
+ /* Continue */
+ break;
+ }
+
+ /* Handle only SOP messages */
+ if (type != TCPCI_MSG_SOP) {
+ return;
+ }
+
+ /* Call drp specific handler */
+ processed = tcpci_drp_emul_handle_sop_msg(&drp_emul->data,
+ &drp_emul->src_data,
+ &drp_emul->snk_data,
+ &drp_emul->common_data,
+ ops, tx_msg);
+ if (processed == TCPCI_PARTNER_COMMON_MSG_HANDLED) {
+ return;
+ }
+
+ /* Call source specific handler */
+ processed = tcpci_src_emul_handle_sop_msg(&drp_emul->src_data,
+ &drp_emul->common_data,
+ tx_msg);
+ if (processed == TCPCI_PARTNER_COMMON_MSG_HANDLED) {
+ return;
+ }
+
+ /* Call sink specific handler */
+ processed = tcpci_snk_emul_handle_sop_msg(&drp_emul->snk_data,
+ &drp_emul->common_data,
+ tx_msg);
+ if (processed == TCPCI_PARTNER_COMMON_MSG_HANDLED) {
+ return;
+ }
+
+ /* Send reject for not handled messages (PD rev 2.0) */
+ tcpci_partner_send_control_msg(&drp_emul->common_data,
+ PD_CTRL_REJECT, 0);
+}
+
+/**
+ * @brief Function called when TCPM consumes message. Free message that is no
+ * longer needed.
+ *
+ * @param emul Pointer to TCPCI emulator
+ * @param ops Pointer to partner operations structure
+ * @param rx_msg Message that was consumed by TCPM
+ */
+static void tcpci_drp_emul_rx_consumed_op(
+ const struct emul *emul,
+ const struct tcpci_emul_partner_ops *ops,
+ const struct tcpci_emul_msg *rx_msg)
+{
+ struct tcpci_partner_msg *msg = CONTAINER_OF(rx_msg,
+ struct tcpci_partner_msg,
+ msg);
+
+ tcpci_partner_free_msg(msg);
+}
+
+/** Check description in emul_tcpci_partner_drp.h */
+int tcpci_drp_emul_connect_to_tcpci(struct tcpci_drp_emul_data *data,
+ struct tcpci_src_emul_data *src_data,
+ struct tcpci_snk_emul_data *snk_data,
+ struct tcpci_partner_data *common_data,
+ const struct tcpci_emul_partner_ops *ops,
+ const struct emul *tcpci_emul)
+{
+ if (data->sink) {
+ return tcpci_snk_emul_connect_to_tcpci(snk_data, common_data,
+ ops, tcpci_emul);
+ }
+
+ return tcpci_src_emul_connect_to_tcpci(src_data, common_data,
+ ops, tcpci_emul);
+}
+
+/** Check description in emul_tcpci_partner_drp.h */
+void tcpci_drp_emul_init(struct tcpci_drp_emul *emul)
+{
+ tcpci_partner_init(&emul->common_data);
+
+ /* By default init as sink */
+ emul->common_data.data_role = PD_ROLE_DFP;
+ emul->common_data.power_role = PD_ROLE_SINK;
+ emul->common_data.rev = PD_REV20;
+
+ emul->ops.transmit = tcpci_drp_emul_transmit_op;
+ emul->ops.rx_consumed = tcpci_drp_emul_rx_consumed_op;
+ emul->ops.control_change = NULL;
+
+ emul->data.sink = true;
+ emul->data.in_pwr_swap = false;
+ tcpci_src_emul_init_data(&emul->src_data);
+ tcpci_snk_emul_init_data(&emul->snk_data);
+
+ /* Add dual role bit to sink and source PDOs */
+ emul->src_data.pdo[0] |= PDO_FIXED_DUAL_ROLE;
+ emul->snk_data.pdo[0] |= PDO_FIXED_DUAL_ROLE;
+}
diff --git a/zephyr/include/emul/tcpc/emul_tcpci_partner_drp.h b/zephyr/include/emul/tcpc/emul_tcpci_partner_drp.h
new file mode 100644
index 0000000000..bb79ef5472
--- /dev/null
+++ b/zephyr/include/emul/tcpc/emul_tcpci_partner_drp.h
@@ -0,0 +1,109 @@
+/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/**
+ * @file
+ *
+ * @brief Backend API for USB-C dual role device emulator
+ */
+
+#ifndef __EMUL_TCPCI_PARTNER_DRP_H
+#define __EMUL_TCPCI_PARTNER_DRP_H
+
+#include <emul.h>
+#include "emul/tcpc/emul_tcpci.h"
+#include "emul/tcpc/emul_tcpci_partner_common.h"
+#include "emul/tcpc/emul_tcpci_partner_snk.h"
+#include "emul/tcpc/emul_tcpci_partner_src.h"
+#include "usb_pd.h"
+
+/**
+ * @brief USB-C dual role device emulator backend API
+ * @defgroup tcpci_snk_emul USB-C dual role device emulator
+ * @{
+ *
+ * USB-C DRP device emulator can be attached to TCPCI emulator as sink or
+ * source device. It is able to switch power role on PR SWAP message. It is able
+ * to send both source and sink capabilities.
+ */
+
+/** Structure describing dual role device emulator data */
+struct tcpci_drp_emul_data {
+ /** Controls if device is sink or source */
+ bool sink;
+ /** If device is during power swap and is expecting PS_RDY message */
+ bool in_pwr_swap;
+};
+
+/** Structure describing standalone dual role device emulator */
+struct tcpci_drp_emul {
+ /** Common TCPCI partner data */
+ struct tcpci_partner_data common_data;
+ /** Operations used by TCPCI emulator */
+ struct tcpci_emul_partner_ops ops;
+ /** Dual role emulator data */
+ struct tcpci_drp_emul_data data;
+ /** Source emulator data */
+ struct tcpci_src_emul_data src_data;
+ /** Sink emulator data */
+ struct tcpci_snk_emul_data snk_data;
+};
+
+/**
+ * @brief Initialise USB-C dual role device emulator. Need to be called before
+ * any other function that is using common_data.
+ *
+ * @param emul Pointer to USB-C dual role device emulator
+ */
+void tcpci_drp_emul_init(struct tcpci_drp_emul *emul);
+
+/**
+ * @brief Connect emulated device to TCPCI. Connect as sink or source depending
+ * on sink field in @p data structure. @p common_data power_role field
+ * should be set correctly before calling this function.
+ *
+ * @param data Pointer to USB-C dual role device emulator data
+ * @param src_data Pointer to USB-C source device emulator data
+ * @param snk_data Pointer to USB-C sink device emulator data
+ * @param common_data Pointer to common TCPCI partner data
+ * @param ops Pointer to TCPCI partner emulator operations
+ * @param tcpci_emul Pointer to TCPCI emulator to connect
+ *
+ * @return 0 on success
+ * @return negative on TCPCI connect error
+ */
+int tcpci_drp_emul_connect_to_tcpci(struct tcpci_drp_emul_data *data,
+ struct tcpci_src_emul_data *src_data,
+ struct tcpci_snk_emul_data *snk_data,
+ struct tcpci_partner_data *common_data,
+ const struct tcpci_emul_partner_ops *ops,
+ const struct emul *tcpci_emul);
+
+/**
+ * @brief Handle SOP messages as TCPCI dual role device
+ *
+ * @param data Pointer to USB-C dual role device emulator data
+ * @param src_data Pointer to USB-C source device emulator data
+ * @param snk_data Pointer to USB-C sink device emulator data
+ * @param common_data Pointer to common TCPCI partner data
+ * @param ops Pointer to TCPCI partner emulator operations
+ * @param msg Pointer to received message
+ *
+ * @return TCPCI_PARTNER_COMMON_MSG_HANDLED Message was handled
+ * @return TCPCI_PARTNER_COMMON_MSG_NOT_HANDLED Message wasn't handled
+ */
+enum tcpci_partner_handler_res tcpci_drp_emul_handle_sop_msg(
+ struct tcpci_drp_emul_data *data,
+ struct tcpci_src_emul_data *src_data,
+ struct tcpci_snk_emul_data *snk_data,
+ struct tcpci_partner_data *common_data,
+ const struct tcpci_emul_partner_ops *ops,
+ const struct tcpci_emul_msg *msg);
+
+/**
+ * @}
+ */
+
+#endif /* __EMUL_TCPCI_PARTNER_DRP_H */