summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/dingdong/usb_pd_policy.c46
-rw-r--r--board/fruitpie/usb_pd_policy.c7
-rw-r--r--board/hoho/usb_pd_policy.c46
-rw-r--r--board/samus_pd/usb_pd_policy.c42
-rw-r--r--common/usb_pd_policy.c82
-rw-r--r--common/usb_pd_protocol.c6
-rw-r--r--include/usb_pd.h5
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
* -------------------------