diff options
-rw-r--r-- | board/kukui/gpio.inc | 2 | ||||
-rw-r--r-- | board/kukui/usb_pd_policy.c | 67 |
2 files changed, 58 insertions, 11 deletions
diff --git a/board/kukui/gpio.inc b/board/kukui/gpio.inc index b67489fb60..720eaa42c5 100644 --- a/board/kukui/gpio.inc +++ b/board/kukui/gpio.inc @@ -99,7 +99,7 @@ GPIO(EC_INT_L, PIN(B, 12), GPIO_ODR_HIGH) /* EC_AP_INT_ODL */ GPIO(EC_BOARD_ID_EN_L, PIN(C, 15), GPIO_ODR_HIGH) /* EC_BOARD_ID_EN_ODL */ GPIO(USB_C0_DISCHARGE, PIN(B, 0), GPIO_OUT_LOW) GPIO(USB_C0_DP_POLARITY, PIN(C, 14), GPIO_OUT_LOW) -GPIO(USB_C0_HPD_OD, PIN(F, 1), GPIO_ODR_HIGH) +GPIO(USB_C0_HPD_OD, PIN(F, 1), GPIO_ODR_LOW) GPIO(BOOTBLOCK_MUX_OE, PIN(C, 4), GPIO_ODR_HIGH) GPIO(BOOTBLOCK_EN_L, PIN(C, 1), GPIO_ODR_HIGH) #if BOARD_REV == 0 diff --git a/board/kukui/usb_pd_policy.c b/board/kukui/usb_pd_policy.c index c3bfa25760..42b0ce7e03 100644 --- a/board/kukui/usb_pd_policy.c +++ b/board/kukui/usb_pd_policy.c @@ -273,37 +273,84 @@ static int svdm_dp_config(int port, uint32_t *payload) return 2; }; +/* + * timestamp of the next possible toggle to ensure the 2-ms spacing + * between IRQ_HPD. + */ +static uint64_t hpd_deadline[CONFIG_USB_PD_PORT_COUNT]; + static void svdm_dp_post_config(int port) { + const struct usb_mux * const mux = &usb_muxes[port]; + dp_flags[port] |= DP_FLAGS_DP_ON; + if (!(dp_flags[port] & DP_FLAGS_HPD_HI_PENDING)) + return; + + gpio_set_level(GPIO_USB_C0_HPD_OD, 1); + gpio_set_level(GPIO_USB_C0_DP_OE_L, 0); + gpio_set_level(GPIO_USB_C0_DP_POLARITY, pd_get_polarity(port)); + + /* set the minimum time delay (2ms) for the next HPD IRQ */ + hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL; + mux->hpd_update(port, 1, 0); } static int svdm_dp_attention(int port, uint32_t *payload) { - const struct usb_mux *mux = &usb_muxes[port]; + int cur_lvl = gpio_get_level(GPIO_USB_C0_HPD_OD); int lvl = PD_VDO_DPSTS_HPD_LVL(payload[1]); int irq = PD_VDO_DPSTS_HPD_IRQ(payload[1]); - int mf_pref = PD_VDO_DPSTS_MF_PREF(payload[1]); + const struct usb_mux * const mux = &usb_muxes[port]; dp_status[port] = payload[1]; - mux->hpd_update(port, lvl, irq); + /* Its initial DP status message prior to config */ + if (!(dp_flags[port] & DP_FLAGS_DP_ON)) { + if (lvl) + dp_flags[port] |= DP_FLAGS_HPD_HI_PENDING; + return 1; + } - if (lvl) - usb_mux_set(port, mf_pref ? TYPEC_MUX_DOCK : TYPEC_MUX_DP, - USB_SWITCH_CONNECT, pd_get_polarity(port)); - else - usb_mux_set(port, mf_pref ? TYPEC_MUX_USB : TYPEC_MUX_NONE, - USB_SWITCH_CONNECT, pd_get_polarity(port)); + if (irq & cur_lvl) { + uint64_t now = get_time().val; + /* wait for the minimum spacing between IRQ_HPD if needed */ + if (now < hpd_deadline[port]) + usleep(hpd_deadline[port] - now); + + /* generate IRQ_HPD pulse */ + gpio_set_level(GPIO_USB_C0_HPD_OD, 0); + usleep(HPD_DSTREAM_DEBOUNCE_IRQ); + gpio_set_level(GPIO_USB_C0_HPD_OD, 1); + + gpio_set_level(GPIO_USB_C0_DP_OE_L, 0); + gpio_set_level(GPIO_USB_C0_DP_POLARITY, pd_get_polarity(port)); + + /* set the minimum time delay (2ms) for the next HPD IRQ */ + hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL; + } else if (irq & !cur_lvl) { + CPRINTF("ERR:HPD:IRQ&LOW\n"); + return 0; /* nak */ + } else { + gpio_set_level(GPIO_USB_C0_HPD_OD, lvl); + gpio_set_level(GPIO_USB_C0_DP_OE_L, !lvl); + gpio_set_level(GPIO_USB_C0_DP_POLARITY, pd_get_polarity(port)); + /* set the minimum time delay (2ms) for the next HPD IRQ */ + hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL; + } + mux->hpd_update(port, lvl, irq); + /* ack */ return 1; } static void svdm_exit_dp_mode(int port) { - const struct usb_mux *mux = &usb_muxes[port]; + const struct usb_mux * const mux = &usb_muxes[port]; svdm_safe_dp_mode(port); + gpio_set_level(GPIO_USB_C0_HPD_OD, 0); + gpio_set_level(GPIO_USB_C0_DP_OE_L, 1); mux->hpd_update(port, 0, 0); } |