diff options
-rw-r--r-- | board/dingdong/usb_pd_policy.c | 46 | ||||
-rw-r--r-- | board/fruitpie/usb_pd_policy.c | 7 | ||||
-rw-r--r-- | board/hoho/usb_pd_policy.c | 46 | ||||
-rw-r--r-- | board/samus_pd/usb_pd_policy.c | 42 | ||||
-rw-r--r-- | common/usb_pd_policy.c | 82 | ||||
-rw-r--r-- | common/usb_pd_protocol.c | 6 | ||||
-rw-r--r-- | include/usb_pd.h | 5 |
7 files changed, 171 insertions, 63 deletions
diff --git a/board/dingdong/usb_pd_policy.c b/board/dingdong/usb_pd_policy.c index fa0894e509..97504a1cbf 100644 --- a/board/dingdong/usb_pd_policy.c +++ b/board/dingdong/usb_pd_policy.c @@ -124,7 +124,14 @@ static int svdm_response_svids(int port, uint32_t *payload) return 2; } -const uint32_t vdo_dp_mode[1] = { +/* Will only ever be a single mode for this UFP_D device as it has no USB + * support (2.0 or 3.0) making it only PIN_E configureable nor does it have any + * source functionality. + */ +#define MODE_CNT 1 +#define OPOS 1 + +const uint32_t vdo_dp_mode[MODE_CNT] = { VDO_MODE_DP(0, /* UFP pin cfg supported : none */ MODE_DP_PIN_E, /* DFP pin cfg supported */ 1, /* no usb2.0 signalling in AMode */ @@ -135,57 +142,46 @@ const uint32_t vdo_dp_mode[1] = { static int svdm_response_modes(int port, uint32_t *payload) { - int mode_cnt = ARRAY_SIZE(vdo_dp_mode); - if (PD_VDO_VID(payload[0]) != USB_SID_DISPLAYPORT) { /* TODO(tbroch) USB billboard enabled here then */ return 1; /* will generate a NAK */ } memcpy(payload + 1, vdo_dp_mode, sizeof(vdo_dp_mode)); - return mode_cnt + 1; -} - -static int hpd_get_irq(int port) -{ - /* TODO(tbroch) FIXME */ - return 0; -} - -static enum hpd_level hpd_get_level(int port) -{ - /* TODO(tbroch) FIXME: needs debounce */ - return gpio_get_level(GPIO_DP_HPD); + return MODE_CNT + 1; } static int dp_status(int port, uint32_t *payload) { - uint32_t ufp_dp_sts = payload[1] & 0x3; - payload[1] = VDO_DP_STATUS(hpd_get_irq(port), /* IRQ_HPD */ - hpd_get_level(port), /* HPD_HI|LOW */ + int opos = PD_VDO_OPOS(payload[0]); + int hpd = gpio_get_level(GPIO_DP_HPD); + if (opos != OPOS) + return 0; /* nak */ + + payload[1] = VDO_DP_STATUS(0, /* IRQ_HPD */ + (hpd == 1), /* HPD_HI|LOW */ 0, /* request exit DP */ 0, /* request exit USB */ 0, /* MF pref */ gpio_get_level(GPIO_PD_SBU_ENABLE), 0, /* power low */ - (ufp_dp_sts | 0x2)); + 0x2); return 2; } static int dp_config(int port, uint32_t *payload) { - if (PD_DP_CFG_DPON(payload[1])) { + if (PD_DP_CFG_DPON(payload[1])) gpio_set_level(GPIO_PD_SBU_ENABLE, 1); - payload[1] = 0; - } - return 2; + + return 1; } static int svdm_enter_mode(int port, uint32_t *payload) { /* SID & mode request is valid */ if ((PD_VDO_VID(payload[0]) != USB_SID_DISPLAYPORT) || - (PD_VDO_OPOS(payload[0]) != 1)) + (PD_VDO_OPOS(payload[0]) != OPOS)) return 0; /* will generate NAK */ return 1; } diff --git a/board/fruitpie/usb_pd_policy.c b/board/fruitpie/usb_pd_policy.c index 6caea5692f..aa63911cc9 100644 --- a/board/fruitpie/usb_pd_policy.c +++ b/board/fruitpie/usb_pd_policy.c @@ -224,6 +224,12 @@ static int svdm_dp_config(int port, uint32_t *payload) return 2; }; +static int svdm_dp_attention(int port, uint32_t *payload) +{ + CPRINTF("dp sts:%08x\n", payload[1]); + return 1; /* ack */ +} + static void svdm_exit_dp_mode(int port) { CPRINTF("Exiting mode\n"); @@ -236,6 +242,7 @@ const struct svdm_amode_fx supported_modes[] = { .enter = &svdm_enter_dp_mode, .status = &svdm_dp_status, .config = &svdm_dp_config, + .attention = &svdm_dp_attention, .exit = &svdm_exit_dp_mode, }, }; diff --git a/board/hoho/usb_pd_policy.c b/board/hoho/usb_pd_policy.c index 61457d3d6c..b747766aa9 100644 --- a/board/hoho/usb_pd_policy.c +++ b/board/hoho/usb_pd_policy.c @@ -124,7 +124,14 @@ static int svdm_response_svids(int port, uint32_t *payload) return 2; } -const uint32_t vdo_dp_mode[1] = { +/* Will only ever be a single mode for this UFP_D device as it has no USB + * support (2.0 or 3.0) making it only PIN_E configureable nor does it have any + * source functionality. + */ +#define MODE_CNT 1 +#define OPOS 1 + +const uint32_t vdo_dp_mode[MODE_CNT] = { VDO_MODE_DP(0, /* UFP pin cfg supported : none */ MODE_DP_PIN_C, /* DFP pin cfg supported */ 1, /* no usb2.0 signalling in AMode */ @@ -135,39 +142,30 @@ const uint32_t vdo_dp_mode[1] = { static int svdm_response_modes(int port, uint32_t *payload) { - int mode_cnt = ARRAY_SIZE(vdo_dp_mode); - if (PD_VDO_VID(payload[0]) != USB_SID_DISPLAYPORT) { /* TODO(tbroch) USB billboard enabled here then */ return 1; /* will generate a NAK */ } memcpy(payload + 1, vdo_dp_mode, sizeof(vdo_dp_mode)); - return mode_cnt + 1; -} - -static int hpd_get_irq(int port) -{ - /* TODO(tbroch) FIXME */ - return 0; -} - -static enum hpd_level hpd_get_level(int port) -{ - return gpio_get_level(GPIO_DP_HPD); + return MODE_CNT + 1; } static int dp_status(int port, uint32_t *payload) { - uint32_t ufp_dp_sts = payload[1] & 0x3; - payload[1] = VDO_DP_STATUS(hpd_get_irq(port), /* IRQ_HPD */ - hpd_get_level(port), /* HPD_HI|LOW */ - 0, /* request exit DP */ - 0, /* request exit USB */ - 0, /* MF pref */ + int opos = PD_VDO_OPOS(payload[0]); + int hpd = gpio_get_level(GPIO_DP_HPD); + if (opos != OPOS) + return 0; /* nak */ + + payload[1] = VDO_DP_STATUS(0, /* IRQ_HPD */ + (hpd == 1), /* HPD_HI|LOW */ + 0, /* request exit DP */ + 0, /* request exit USB */ + 0, /* MF pref */ gpio_get_level(GPIO_PD_SBU_ENABLE), - 0, /* power low */ - (ufp_dp_sts | 0x2)); + 0, /* power low */ + 0x2); return 2; } @@ -182,7 +180,7 @@ static int svdm_enter_mode(int port, uint32_t *payload) { /* SID & mode request is valid */ if ((PD_VDO_VID(payload[0]) != USB_SID_DISPLAYPORT) || - (PD_VDO_OPOS(payload[0]) != 1)) + (PD_VDO_OPOS(payload[0]) != OPOS)) return 0; /* will generate a NAK */ return 1; } diff --git a/board/samus_pd/usb_pd_policy.c b/board/samus_pd/usb_pd_policy.c index e8ffd2a886..507c6d3bce 100644 --- a/board/samus_pd/usb_pd_policy.c +++ b/board/samus_pd/usb_pd_policy.c @@ -7,6 +7,7 @@ #include "common.h" #include "console.h" #include "gpio.h" +#include "hooks.h" #include "host_command.h" #include "registers.h" #include "task.h" @@ -275,9 +276,49 @@ static int svdm_dp_config(int port, uint32_t *payload) return 2; }; +static void hpd0_irq_deferred(void) +{ + gpio_set_level(GPIO_USB_C0_DP_HPD, 1); +} + +static void hpd1_irq_deferred(void) +{ + gpio_set_level(GPIO_USB_C1_DP_HPD, 1); +} + +DECLARE_DEFERRED(hpd0_irq_deferred); +DECLARE_DEFERRED(hpd1_irq_deferred); + +#define PORT_TO_HPD(port) ((port) ? GPIO_USB_C1_DP_HPD : GPIO_USB_C0_DP_HPD) + +static int svdm_dp_attention(int port, uint32_t *payload) +{ + int cur_lvl; + int lvl = PD_VDO_HPD_LVL(payload[1]); + int irq = PD_VDO_HPD_IRQ(payload[1]); + enum gpio_signal hpd = PORT_TO_HPD(port); + cur_lvl = gpio_get_level(hpd); + if (irq & cur_lvl) { + gpio_set_level(hpd, 0); + /* 250 usecs is minimum, 2msec is max */ + if (port) + hook_call_deferred(hpd1_irq_deferred, 300); + else + hook_call_deferred(hpd0_irq_deferred, 300); + } else if (irq & !cur_lvl) { + CPRINTF("PE ERR: IRQ_HPD w/ HPD_LOW\n"); + return 0; /* nak */ + } else { + gpio_set_level(hpd, lvl); + } + /* ack */ + return 1; +} + static void svdm_exit_dp_mode(int port) { svdm_safe_dp_mode(port); + gpio_set_level(PORT_TO_HPD(port), 0); } const struct svdm_amode_fx supported_modes[] = { @@ -286,6 +327,7 @@ const struct svdm_amode_fx supported_modes[] = { .enter = &svdm_enter_dp_mode, .status = &svdm_dp_status, .config = &svdm_dp_config, + .attention = &svdm_dp_attention, .exit = &svdm_exit_dp_mode, }, }; diff --git a/common/usb_pd_policy.c b/common/usb_pd_policy.c index 837ef2f5fd..87f6984c88 100644 --- a/common/usb_pd_policy.c +++ b/common/usb_pd_policy.c @@ -23,11 +23,14 @@ #ifdef CONFIG_USB_PD_ALT_MODE_DFP -struct pd_policy pe[PD_PORT_COUNT]; +static struct pd_policy pe[PD_PORT_COUNT]; + +#define AMODE_VALID(port) (pe[port].amode.index != -1) static void pe_init(int port) { - memset(pe, 0, sizeof(struct pd_policy) * PD_PORT_COUNT); + memset(&pe[port], 0, sizeof(struct pd_policy)); + pe[port].amode.index = -1; } static void dfp_consume_identity(int port, uint32_t *payload) @@ -114,7 +117,6 @@ static int dfp_enter_mode(int port, uint32_t *payload) { int i, j, done; struct svdm_amode_data *modep = &pe[port].amode; - pe[port].amode.index = -1; /* Error condition */ for (i = 0, done = 0; !done && (i < supported_modes_cnt); i++) { for (j = 0; j < pe[port].svid_cnt; j++) { if (pe[port].svids[j].svid != supported_modes[i].svid) @@ -127,7 +129,7 @@ static int dfp_enter_mode(int port, uint32_t *payload) break; } } - if (modep->index == -1) + if (!AMODE_VALID(port)) return 0; modep->fx->enter(port, modep->mode_caps); @@ -137,13 +139,40 @@ static int dfp_enter_mode(int port, uint32_t *payload) return 1; } +static int dfp_consume_attention(int port, uint32_t *payload) +{ + int svid = PD_VDO_VID(payload[0]); + int opos = PD_VDO_OPOS(payload[0]); + + if (!AMODE_VALID(port)) + return 0; + if (svid != pe[port].amode.fx->svid) { + CPRINTF("PE ERR: svid s:0x%04x != m:0x%04x\n", + svid, pe[port].amode.fx->svid); + return 0; /* NAK */ + } + if (opos != pe[port].amode.index + 1) { + CPRINTF("PE ERR: opos s:%d != m:%d\n", + opos, pe[port].amode.index + 1); + return 0; /* NAK */ + } + if (!pe[port].amode.fx->attention) + return 0; + return pe[port].amode.fx->attention(port, payload); +} + int pd_exit_mode(int port, uint32_t *payload) { struct svdm_amode_data *modep = &pe[port].amode; + if (!modep->fx) + return 0; + modep->fx->exit(port); - payload[0] = VDO(modep->fx->svid, 1, - CMD_EXIT_MODE | - VDO_OPOS((modep->index + 1))); + + if (payload) + payload[0] = VDO(modep->fx->svid, 1, + CMD_EXIT_MODE | VDO_OPOS((modep->index + 1))); + modep->index = -1; return 1; } @@ -163,7 +192,7 @@ static void dump_pe(int port) pe[port].svids[i].mode_vdo[j]); ccprintf("\n"); } - if (pe[port].amode.index == -1) { + if (!AMODE_VALID(port)) { ccprintf("No mode chosen yet.\n"); return; } @@ -234,6 +263,15 @@ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload) case CMD_EXIT_MODE: func = svdm_rsp.exit_mode; break; +#ifdef CONFIG_USB_PD_ALT_MODE_DFP + case CMD_ATTENTION: + /* This is DFP response */ + func = &dfp_consume_attention; + break; +#endif + default: + CPRINTF("PE ERR: unknown command %d\n", cmd); + rsize = 0; } if (func) rsize = func(port, payload); @@ -266,23 +304,42 @@ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload) rsize = dfp_enter_mode(port, payload); break; case CMD_ENTER_MODE: - if (pe[port].amode.index != -1) + if (AMODE_VALID(port)) { rsize = pe[port].amode.fx->status(port, payload); + payload[0] |= + VDO_OPOS((pe[port].amode.index + 1)); + } else { + rsize = 0; + } break; case CMD_DP_STATUS: - rsize = pe[port].amode.fx->config(port, payload); + /* DP status response & UFP's DP attention have same + payload */ + dfp_consume_attention(port, payload); + if (AMODE_VALID(port)) + rsize = pe[port].amode.fx->config(port, + payload); + else + rsize = 0; break; case CMD_DP_CONFIG: + /* no response after DFPs ack */ rsize = 0; break; case CMD_EXIT_MODE: - rsize = pd_exit_mode(port, payload); + /* no response after DFPs ack */ + rsize = 0; + break; + case CMD_ATTENTION: + /* no response after DFPs ack */ + rsize = 0; break; default: + CPRINTF("PE ERR: unknown command %d\n", cmd); rsize = 0; } - payload[0] &= ~VDO_CMDT(0); + payload[0] |= VDO_CMDT(CMDT_INIT); } else if (cmd_type == CMDT_RSP_BUSY) { switch (cmd) { @@ -290,7 +347,6 @@ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload) case CMD_DISCOVER_SVID: case CMD_DISCOVER_MODES: /* resend if its discovery */ - payload[0] &= ~VDO_CMDT(0); payload[0] |= VDO_CMDT(CMDT_INIT); rsize = 1; break; diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 3c4106afb8..fa85ac5643 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -302,10 +302,14 @@ static inline void set_state(int port, enum pd_states next_state) if (next_state == PD_STATE_SRC_DISCONNECTED) { pd[port].dev_id = 0; +#ifdef CONFIG_USB_PD_ALT_MODE_DFP + pd_exit_mode(port, NULL); +#else #ifdef CONFIG_USBC_SS_MUX board_set_usb_mux(port, TYPEC_MUX_NONE, pd[port].polarity); #endif +#endif #ifdef CONFIG_USBC_VCONN pd_set_vconn(port, pd[port].polarity, 0); #endif @@ -1559,7 +1563,7 @@ void pd_task(void) hard_reset_count++; #endif - pd_exit_mode(port, payload); + pd_exit_mode(port, NULL); send_hard_reset(port); /* reset our own state machine */ execute_hard_reset(port); diff --git a/include/usb_pd.h b/include/usb_pd.h index 4518d2e88b..2184f19230 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -133,6 +133,7 @@ struct svdm_amode_fx { void (*enter)(int port, uint32_t mode_caps); int (*status)(int port, uint32_t *payload); int (*config)(int port, uint32_t *payload); + int (*attention)(int port, uint32_t *payload); void (*exit)(int port); }; @@ -194,6 +195,7 @@ struct pd_policy { #define VDO_SVDM_VERS(x) (x << 13) #define VDO_OPOS(x) (x << 8) #define VDO_CMDT(x) (x << 6) +#define VDO_OPOS_MASK VDO_OPOS(0x7) #define VDO_CMDT_MASK VDO_CMDT(0x3) #define CMDT_INIT 0 @@ -409,6 +411,9 @@ struct pd_policy { (((irq) & 1) << 8 | ((lvl) & 1) << 7 | ((amode) & 1) << 6 \ | ((usbc) & 1) << 5 | ((mf) & 1) << 4 | ((en) & 1) << 3 \ | ((lp) & 1) << 2 | ((conn & 0x3) << 0)) + +#define PD_VDO_HPD_IRQ(x) ((x >> 8) & 1) +#define PD_VDO_HPD_LVL(x) ((x >> 7) & 1) /* * DisplayPort Configure VDO * ------------------------- |