summaryrefslogtreecommitdiff
path: root/zephyr
diff options
context:
space:
mode:
authorEric Yilun Lin <yllin@chromium.org>2022-02-18 16:33:33 +0800
committerCommit Bot <commit-bot@chromium.org>2022-02-24 09:43:54 +0000
commit5276c82511b7485aaa7acfbf21b752c31eb29643 (patch)
treeb0e9e84bed32c433ffcd0558c3303807b77c4688 /zephyr
parente374e796a6c97f8178faf0659acb358c9fe1b750 (diff)
downloadchrome-ec-5276c82511b7485aaa7acfbf21b752c31eb29643.tar.gz
corsola: support HDMI HPD over virtual mux and type-c DP
Initialize USB-C port num to 2 after tasks associated with port 1 exit, and we can safely simulate HDMI1 over C1 mux. Simulate HDMI HPD event over C1 virtual mux, and type-c DP. HPD high -> virtual mux set DP connected HPD low for 2 ms -> virtual mux set DP disconnected This CL saves 2 GPIOs to AP and re-use the existing ANX7625 driver without changing. BUG=b:216021294 TEST=1. plug hdmi, unplug HDMI, and virtual mux, and DP status can be updated accordingly. 2. See HDMI port output 3. ectool typec 0|1 BRANCH=none Change-Id: Icbf35523770a6eeda6ac970573738373ecdf849b Signed-off-by: Eric Yilun Lin <yllin@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3474551 Reviewed-by: Ting Shen <phoenixshen@chromium.org> Commit-Queue: Eric Yilun Lin <yllin@google.com> Tested-by: Eric Yilun Lin <yllin@google.com> Auto-Submit: Eric Yilun Lin <yllin@google.com>
Diffstat (limited to 'zephyr')
-rw-r--r--zephyr/projects/corsola/include/baseboard_usbc_config.h10
-rw-r--r--zephyr/projects/corsola/src/usb_pd_policy.c14
-rw-r--r--zephyr/projects/corsola/src/usbc_config.c129
3 files changed, 130 insertions, 23 deletions
diff --git a/zephyr/projects/corsola/include/baseboard_usbc_config.h b/zephyr/projects/corsola/include/baseboard_usbc_config.h
index 60f61e72f3..1d6fb33128 100644
--- a/zephyr/projects/corsola/include/baseboard_usbc_config.h
+++ b/zephyr/projects/corsola/include/baseboard_usbc_config.h
@@ -28,4 +28,14 @@ enum usbc_port {
};
BUILD_ASSERT(USBC_PORT_COUNT == CONFIG_USB_PD_PORT_MAX_COUNT);
+/**
+ * Is the port fine to be muxed its DisplayPort lines?
+ *
+ * Only one port can be muxed to DisplayPort at a time.
+ *
+ * @param port Port number of TCPC.
+ * @return 1 is fine; 0 is bad as other port is already muxed;
+ */
+int corsola_is_dp_muxable(int port);
+
#endif /* __CROS_EC_BASEBOARD_USBC_CONFIG_H */
diff --git a/zephyr/projects/corsola/src/usb_pd_policy.c b/zephyr/projects/corsola/src/usb_pd_policy.c
index 88eb297694..790c830c17 100644
--- a/zephyr/projects/corsola/src/usb_pd_policy.c
+++ b/zephyr/projects/corsola/src/usb_pd_policy.c
@@ -11,6 +11,8 @@
#include "usb_pd.h"
#include "usbc_ppc.h"
+#include "baseboard_usbc_config.h"
+
#if CONFIG_USB_PD_3A_PORTS != 1
#error Corsola reference must have at least one 3.0 A port
#endif
@@ -39,15 +41,7 @@ void svdm_set_hpd_gpio(int port, int en)
gpio_pin_set_dt(GPIO_DT_FROM_NODELABEL(ec_ap_dp_hpd_odl), !en);
}
-/**
- * Is the port fine to be muxed its DisplayPort lines?
- *
- * Only one port can be muxed to DisplayPort at a time.
- *
- * @param port Port number of TCPC.
- * @return 1 is fine; 0 is bad as other port is already muxed;
- */
-static int is_dp_muxable(int port)
+int corsola_is_dp_muxable(int port)
{
int i;
@@ -72,7 +66,7 @@ __override int svdm_dp_attention(int port, uint32_t *payload)
dp_status[port] = payload[1];
- if (!is_dp_muxable(port)) {
+ if (!corsola_is_dp_muxable(port)) {
/* TODO(waihong): Info user? */
CPRINTS("p%d: The other port is already muxed.", port);
return 0; /* nak */
diff --git a/zephyr/projects/corsola/src/usbc_config.c b/zephyr/projects/corsola/src/usbc_config.c
index 569db96a19..0f5072b546 100644
--- a/zephyr/projects/corsola/src/usbc_config.c
+++ b/zephyr/projects/corsola/src/usbc_config.c
@@ -36,6 +36,9 @@
#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args)
#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args)
+/* a flag for indicating the tasks are inited. */
+static bool tasks_inited;
+
/* Baseboard */
static void baseboard_init(void)
{
@@ -45,15 +48,6 @@ static void baseboard_init(void)
}
DECLARE_HOOK(HOOK_INIT, baseboard_init, HOOK_PRIO_DEFAULT-1);
-static void baseboard_tcpc_init(void)
-{
- /* If this is not a Type-C subboard, disable the task. */
- if (corsola_get_db_type() != CORSOLA_DB_TYPEC)
- task_disable_task(TASK_ID_PD_C1);
-}
-/* Must be done after I2C and subboard */
-DECLARE_HOOK(HOOK_INIT, baseboard_tcpc_init, HOOK_PRIO_INIT_I2C + 1);
-
static void baseboard_x_ec_gpio2_init(void)
{
/* type-c: USB_C1_PPC_INT_ODL / hdmi: PS185_EC_DP_HPD */
@@ -63,10 +57,14 @@ DECLARE_HOOK(HOOK_INIT, baseboard_x_ec_gpio2_init, HOOK_PRIO_DEFAULT);
__override uint8_t board_get_usb_pd_port_count(void)
{
- if (corsola_get_db_type() == CORSOLA_DB_TYPEC)
- return CONFIG_USB_PD_PORT_MAX_COUNT;
- else
- return CONFIG_USB_PD_PORT_MAX_COUNT - 1;
+ if (corsola_get_db_type() == CORSOLA_DB_HDMI) {
+ if (tasks_inited)
+ return CONFIG_USB_PD_PORT_MAX_COUNT;
+ else
+ return CONFIG_USB_PD_PORT_MAX_COUNT - 1;
+ }
+
+ return CONFIG_USB_PD_PORT_MAX_COUNT;
}
/* USB-A */
@@ -112,17 +110,74 @@ static void ps185_hdmi_hpd_deferred(void)
debounced_hpd = new_hpd;
+ if (!corsola_is_dp_muxable(USBC_PORT_C1)) {
+ if (debounced_hpd)
+ CPRINTS("C0 port is already muxed.");
+ return;
+ }
+
+ if (debounced_hpd) {
+ dp_status[USBC_PORT_C1] =
+ VDO_DP_STATUS(0, /* HPD IRQ ... not applicable */
+ 0, /* HPD level ... not applicable */
+ 0, /* exit DP? ... no */
+ 0, /* usb mode? ... no */
+ 0, /* multi-function ... no */
+ 1, /* DP enabled ... yes */
+ 0, /* power low? ... no */
+ (!!DP_FLAGS_DP_ON));
+ /* update C1 virtual mux */
+ usb_mux_set(USBC_PORT_C1,
+ USB_PD_MUX_DP_ENABLED,
+ USB_SWITCH_DISCONNECT,
+ 0 /* polarity, don't care */);
+
+ gpio_pin_set_dt(GPIO_DT_FROM_NODELABEL(dp_aux_path_sel),
+ debounced_hpd);
+ CPRINTS("Set DP_AUX_PATH_SEL: %d", 1);
+ }
gpio_pin_set_dt(GPIO_DT_FROM_NODELABEL(ec_ap_dp_hpd_odl),
!debounced_hpd);
CPRINTS(debounced_hpd ? "HDMI plug" : "HDMI unplug");
}
DECLARE_DEFERRED(ps185_hdmi_hpd_deferred);
+static void ps185_hdmi_hpd_disconnect_deferred(void)
+{
+ const int new_hpd = gpio_pin_get_dt(
+ GPIO_DT_FROM_ALIAS(gpio_ps185_ec_dp_hpd));
+
+ if (debounced_hpd == new_hpd && !new_hpd) {
+ dp_status[USBC_PORT_C1] =
+ VDO_DP_STATUS(0, /* HPD IRQ ... not applicable */
+ 0, /* HPD level ... not applicable */
+ 0, /* exit DP? ... no */
+ 0, /* usb mode? ... no */
+ 0, /* multi-function ... no */
+ 0, /* DP enabled ... no */
+ 0, /* power low? ... no */
+ (!DP_FLAGS_DP_ON));
+ usb_mux_set(USBC_PORT_C1, USB_PD_MUX_NONE,
+ USB_SWITCH_DISCONNECT,
+ 0 /* polarity, don't care */);
+ }
+
+}
+DECLARE_DEFERRED(ps185_hdmi_hpd_disconnect_deferred);
+
#define PS185_HPD_DEBOUCE 250
+#define HPD_SINK_ABSENCE_DEBOUNCE (2 * MSEC)
static void hdmi_hpd_interrupt(enum gpio_signal signal)
{
hook_call_deferred(&ps185_hdmi_hpd_deferred_data, PS185_HPD_DEBOUCE);
+
+ if (!gpio_pin_get_dt(GPIO_DT_FROM_ALIAS(gpio_ps185_ec_dp_hpd)))
+ hook_call_deferred(&ps185_hdmi_hpd_disconnect_deferred_data,
+ HPD_SINK_ABSENCE_DEBOUNCE);
+ else
+ hook_call_deferred(&ps185_hdmi_hpd_disconnect_deferred_data,
+ -1);
}
/* HDMI/TYPE-C function shared subboard interrupt */
@@ -152,3 +207,51 @@ void board_hdmi_resume(void)
gpio_pin_set_dt(GPIO_DT_FROM_ALIAS(gpio_ps185_pwrdn_odl), 1);
}
DECLARE_HOOK(HOOK_CHIPSET_RESUME, board_hdmi_resume, HOOK_PRIO_DEFAULT);
+
+static void tasks_init_deferred(void)
+{
+ tasks_inited = true;
+}
+DECLARE_DEFERRED(tasks_init_deferred);
+
+static void hdmi_fix_c1_port(void)
+{
+ static struct ppc_drv virtual_ppc_drv = { 0 };
+ static struct tcpm_drv virtual_tcpc_drv = { 0 };
+ static struct bc12_drv virtual_bc12_drv = { 0 };
+
+ if (corsola_get_db_type() == CORSOLA_DB_TYPEC)
+ return;
+
+ /* drop related C1 port drivers when it's a HDMI DB. */
+ ppc_chips[USBC_PORT_C1] =
+ (const struct ppc_config_t){ .drv = &virtual_ppc_drv };
+ tcpc_config[USBC_PORT_C1] =
+ (const struct tcpc_config_t){ .drv = &virtual_tcpc_drv };
+ bc12_ports[USBC_PORT_C1] =
+ (const struct bc12_config){ .drv = &virtual_bc12_drv };
+ /* Use virtual mux to notify AP the mainlink direction. */
+ usb_muxes[USBC_PORT_C1] = (struct usb_mux){
+ .usb_port = USBC_PORT_C1,
+ .driver = &virtual_usb_mux_driver,
+ .hpd_update = &virtual_hpd_update,
+ };
+
+ /*
+ * If a HDMI DB is attached, C1 port tasks will be exiting in that
+ * the port number is larger than board_get_usb_pd_port_count().
+ * After C1 port tasks finished, we intentionally increase the port
+ * count by 1 for usb_mux to access the C1 virtual mux for notifying
+ * mainlink direction.
+ */
+ hook_call_deferred(&tasks_init_deferred_data, 2 * SECOND);
+}
+DECLARE_HOOK(HOOK_INIT, hdmi_fix_c1_port, HOOK_PRIO_DEFAULT);
+
+__override uint8_t get_dp_pin_mode(int port)
+{
+ if (corsola_get_db_type() == CORSOLA_DB_HDMI && port == USBC_PORT_C1)
+ return MODE_DP_PIN_E;
+
+ return pd_dfp_dp_get_pin_mode(port, dp_status[port]);
+}