pd: allow sink to request new voltage w/o dropping negotiation

Allow a sink to request a new voltage without dropping the established
negotiation. For this to work the sink must save the last received
source cap packet and use that to make a new RDO from the SNK_READY
state.

BUG=chrome-os-partner:30389
BRANCH=none
TEST=Tested on a firefly connected to zinger. made sure we can press
buttons to change voltage and we don't lose the existing negotiation.
Also tested on samus, ports 0 and 1, using pd x dev 5/12/20 to switch
between voltages and verified we don't lose existing negotiation.

Change-Id: I5a550b667f3aff7975185e091f3caac4555a907e
Signed-off-by: Alec Berg <alecaberg@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/209864
Reviewed-by: Vic Yang <victoryang@chromium.org>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
This commit is contained in:
Alec Berg
2014-07-25 09:46:37 -07:00
committed by chrome-internal-fetch
parent 909c3236de
commit f7ed411926
2 changed files with 63 additions and 26 deletions

View File

@@ -217,6 +217,12 @@ enum pd_states {
#ifdef CONFIG_USB_PD_DUAL_ROLE
/* Port dual-role state */
enum pd_dual_role_states drp_state = PD_DRP_TOGGLE_OFF;
/* Last received source cap */
static uint32_t pd_src_caps[PD_PORT_COUNT][PDO_MAX_OBJECTS];
static int pd_src_cap_cnt[PD_PORT_COUNT];
static int new_power_request;
#endif
static struct pd_protocol {
@@ -513,6 +519,44 @@ static void handle_vdm_request(int port, int cnt, uint32_t *payload)
vid, payload[0] & 0xFFFF);
}
#ifdef CONFIG_USB_PD_DUAL_ROLE
static void pd_store_src_cap(int port, int cnt, uint32_t *src_caps)
{
int i;
pd_src_cap_cnt[port] = cnt;
for (i = 0; i < cnt; i++)
pd_src_caps[port][i] = *src_caps++;
}
static void pd_send_request_msg(int port)
{
uint32_t rdo;
int res;
/* we were waiting for them, let's process them */
res = pd_choose_voltage(pd_src_cap_cnt[port], pd_src_caps[port], &rdo);
if (res >= 0) {
res = send_request(port, rdo);
if (res >= 0)
pd[port].task_state =
PD_STATE_SNK_REQUESTED;
else
/*
* for now: ignore failure here,
* we will retry ...
* TODO(crosbug.com/p/28332)
*/
pd[port].task_state =
PD_STATE_SNK_REQUESTED;
}
/*
* TODO(crosbug.com/p/28332): if pd_choose_voltage
* returns an error, ignore failure for now.
*/
}
#endif
static void handle_data_request(int port, uint16_t head,
uint32_t *payload)
{
@@ -523,29 +567,10 @@ static void handle_data_request(int port, uint16_t head,
#ifdef CONFIG_USB_PD_DUAL_ROLE
case PD_DATA_SOURCE_CAP:
if ((pd[port].task_state == PD_STATE_SNK_DISCOVERY)
|| (pd[port].task_state == PD_STATE_SNK_TRANSITION)) {
uint32_t rdo;
int res;
/* we were waiting for them, let's process them */
res = pd_choose_voltage(cnt, payload, &rdo);
if (res >= 0) {
res = send_request(port, rdo);
if (res >= 0)
pd[port].task_state =
PD_STATE_SNK_REQUESTED;
else
/*
* for now: ignore failure here,
* we will retry ...
* TODO(crosbug.com/p/28332)
*/
pd[port].task_state =
PD_STATE_SNK_REQUESTED;
}
/*
* TODO(crosbug.com/p/28332): if pd_choose_voltage
* returns an error, ignore failure for now.
*/
|| (pd[port].task_state == PD_STATE_SNK_TRANSITION)
|| (pd[port].task_state == PD_STATE_SNK_READY)) {
pd_store_src_cap(port, cnt, payload);
pd_send_request_msg(port);
}
break;
#endif /* CONFIG_USB_PD_DUAL_ROLE */
@@ -1080,6 +1105,10 @@ void pd_task(void)
break;
case PD_STATE_SNK_READY:
/* we have power, check vitals from time to time */
if (new_power_request) {
pd_send_request_msg(port);
new_power_request = 0;
}
timeout = 100*MSEC;
break;
#endif /* CONFIG_USB_PD_DUAL_ROLE */
@@ -1142,9 +1171,16 @@ void pd_set_suspend(int port, int enable)
void pd_request_source_voltage(int port, int mv)
{
pd_set_max_voltage(mv);
pd[port].role = PD_ROLE_SINK;
pd_set_host_mode(port, 0);
pd[port].task_state = PD_STATE_SNK_DISCONNECTED;
if (pd[port].task_state == PD_STATE_SNK_READY) {
/* Set flag to send new power request in pd_task */
new_power_request = 1;
} else {
pd[port].role = PD_ROLE_SINK;
pd_set_host_mode(port, 0);
pd[port].task_state = PD_STATE_SNK_DISCONNECTED;
}
task_wake(PORT_TO_TASK_ID(port));
}

View File

@@ -21,6 +21,7 @@ enum pd_errors {
#define PD_EVENT_RX (1<<2)
/* --- PD data message helpers --- */
#define PDO_MAX_OBJECTS 7
/* PDO : Power Data Object */
/*