diff options
author | Eric Yilun Lin <yllin@chromium.org> | 2022-02-18 16:33:33 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2022-02-24 09:43:54 +0000 |
commit | 5276c82511b7485aaa7acfbf21b752c31eb29643 (patch) | |
tree | b0e9e84bed32c433ffcd0558c3303807b77c4688 /zephyr | |
parent | e374e796a6c97f8178faf0659acb358c9fe1b750 (diff) | |
download | chrome-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.h | 10 | ||||
-rw-r--r-- | zephyr/projects/corsola/src/usb_pd_policy.c | 14 | ||||
-rw-r--r-- | zephyr/projects/corsola/src/usbc_config.c | 129 |
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]); +} |