pd: support gotoMin and giveBack

In Sink mode, on the receipt of a GotoMin message,
reduce the current consumption to some minimum level.

BUG=chrome-os-partner:33688
TEST=Manual testing
	Used a Kevin, with test routine, to test GotoMin feature
	on another Kevin unit.

	Test routine:
		 if (!strcasecmp(argv[2], "gm")) {
		    ccprintf("send goto min\n");
		    send_control(port, PD_CTRL_GOTO_MIN);
		    send_control(port, PD_CTRL_PS_RDY);
		}

	Kevin with GotoMin feature:
		# ectool usbpdpower 0
		Port 0: SNK DRP PD 4277mV / 3000mA, max 5000mV / 3000mA / 15000mW
		Port 1: Disconnected

		After Test routine is executed:

		# ectool usbpdpower 0
		Port 0: SNK DRP PD 4906mV / 500mA, max 5000mV / 500mA / 2500mW
		Port 1: Disconnected
BRANCH=none

Change-Id: Iaac6e19706ceb10ccaff4d602d63fc086c808c8f
Reviewed-on: https://chromium-review.googlesource.com/425728
Commit-Ready: Sam Hurst <shurst@google.com>
Tested-by: Sam Hurst <shurst@google.com>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
This commit is contained in:
Sam Hurst 2017-01-10 09:55:37 -08:00 committed by chrome-bot
parent 7736c887d7
commit 17515de32c
11 changed files with 152 additions and 4 deletions

View File

@ -69,4 +69,7 @@ extern const int supplier_priority[];
#define PD_MAX_CURRENT_MA 3000
#define PD_MAX_VOLTAGE_MV 20000
#define PD_MIN_CURRENT_MA 500
#define PD_MIN_POWER_MW 7500
#endif /* __CROS_EC_BOARD_H */

View File

@ -141,6 +141,7 @@
#ifdef BOARD_KEVIN
#define CONFIG_BATTERY_REQUESTS_NIL_WHEN_DEAD
#define CONFIG_USB_PD_GIVE_BACK
#endif
#define PD_OPERATING_POWER_MW 15000
@ -148,6 +149,9 @@
#define PD_MAX_CURRENT_MA 3000
#define PD_MAX_VOLTAGE_MV 20000
#define PD_MIN_CURRENT_MA 500
#define PD_MIN_POWER_MW 2500
#define PD_POWER_SUPPLY_TURN_ON_DELAY 30000 /* us */
#define PD_POWER_SUPPLY_TURN_OFF_DELAY 50000 /* us */
#define PD_VCONN_SWAP_DELAY 5000 /* us */

View File

@ -60,6 +60,16 @@ int board_vbus_source_enabled(int port)
return vbus_en[port];
}
void pd_snk_give_back(int port, uint32_t * const ma, uint32_t * const mv)
{
/* Just reduce the current */
*ma = PD_MIN_CURRENT_MA;
pd_set_input_current_limit(port, *ma, *mv);
#ifdef CONFIG_CHARGE_MANAGER
charge_manager_set_ceil(port, CEIL_REQUESTOR_PD, *ma);
#endif
}
static void board_vbus_update_source_current(int port)
{
enum gpio_signal gpio = port ? GPIO_USB_C1_5V_EN : GPIO_USB_C0_5V_EN;

View File

@ -179,6 +179,8 @@ int pd_build_request(int cnt, uint32_t *src_caps, uint32_t *rdo,
{
int pdo_index, flags = 0;
int uw;
int max_or_min_ma;
int max_or_min_mw;
if (req_type == PD_REQUEST_VSAFE5V)
/* src cap 0 should be vSafe5V */
@ -197,11 +199,35 @@ int pd_build_request(int cnt, uint32_t *src_caps, uint32_t *rdo,
if (uw < (1000 * PD_OPERATING_POWER_MW))
flags |= RDO_CAP_MISMATCH;
#ifdef CONFIG_USB_PD_GIVE_BACK
/* Tell source we are give back capable. */
flags |= RDO_GIVE_BACK;
/*
* BATTERY PDO: Inform the source that the sink will reduce
* power to this minimum level on receipt of a GotoMin Request.
*/
max_or_min_mw = PD_MIN_POWER_MW;
/*
* FIXED or VARIABLE PDO: Inform the source that the sink will reduce
* current to this minimum level on receipt of a GotoMin Request.
*/
max_or_min_ma = PD_MIN_CURRENT_MA;
#else
/*
* Can't give back, so set maximum current and power to operating
* level.
*/
max_or_min_ma = *ma;
max_or_min_mw = uw / 1000;
#endif
if ((src_caps[pdo_index] & PDO_TYPE_MASK) == PDO_TYPE_BATTERY) {
int mw = uw / 1000;
*rdo = RDO_BATT(pdo_index + 1, mw, mw, flags);
*rdo = RDO_BATT(pdo_index + 1, mw, max_or_min_mw, flags);
} else {
*rdo = RDO_FIXED(pdo_index + 1, *ma, *ma, flags);
*rdo = RDO_FIXED(pdo_index + 1, *ma, max_or_min_ma, flags);
}
return EC_SUCCESS;
}

View File

@ -927,6 +927,21 @@ static void handle_ctrl_request(int port, uint16_t head,
break;
#ifdef CONFIG_USB_PD_DUAL_ROLE
case PD_CTRL_GOTO_MIN:
#ifdef CONFIG_USB_PD_GIVE_BACK
if (pd[port].task_state == PD_STATE_SNK_READY) {
/*
* Reduce power consumption now!
*
* The source will restore power to this sink
* by sending a new source cap message at a
* later time.
*/
pd_snk_give_back(port, &pd[port].curr_limit,
&pd[port].supply_voltage);
set_state(port, PD_STATE_SNK_TRANSITION);
}
#endif
break;
case PD_CTRL_PS_RDY:
if (pd[port].task_state == PD_STATE_SNK_SWAP_SRC_DISABLE) {

View File

@ -2140,6 +2140,9 @@
/* Check whether PD is the sole power source before flash erase operation */
#undef CONFIG_USB_PD_FLASH_ERASE_CHECK
/* Define if this board, operating as a sink, can give power back to a source */
#undef CONFIG_USB_PD_GIVE_BACK
/* Major and Minor ChromeOS specific PD device Hardware IDs. */
#undef CONFIG_USB_PD_HW_DEV_ID_BOARD_MAJOR
#undef CONFIG_USB_PD_HW_DEV_ID_BOARD_MINOR

View File

@ -903,6 +903,15 @@ int pd_is_max_request_allowed(void);
*/
void pd_process_source_cap(int port, int cnt, uint32_t *src_caps);
/**
* Reduce the sink power consumption to a minimum value.
*
* @param port USB-C port number
* @param ma reduce current to minimum value.
* @param mv reduce voltage to minimum value.
*/
void pd_snk_give_back(int port, uint32_t * const ma, uint32_t * const mv);
/**
* Put a cap on the max voltage requested as a sink.
* @param mv maximum voltage in millivolts.

View File

@ -71,6 +71,7 @@ test-list-host += system
test-list-host += thermal
test-list-host += timer_dos
test-list-host += usb_pd
test-list-host += usb_pd_giveback
test-list-host += utils
endif
@ -115,4 +116,5 @@ thermal-y=thermal.o
timer_calib-y=timer_calib.o
timer_dos-y=timer_dos.o
usb_pd-y=usb_pd.o
usb_pd_giveback-y=usb_pd.o
utils-y=utils.o

View File

@ -141,7 +141,7 @@ int ncp15wb_calculate_temp(uint16_t adc);
#define CONFIG_ALS_LIGHTBAR_DIMMING 0
#endif
#ifdef TEST_USB_PD
#if defined(TEST_USB_PD) || defined(TEST_USB_PD_GIVEBACK)
#define CONFIG_USB_POWER_DELIVERY
#define CONFIG_USB_PD_CUSTOM_VDM
#define CONFIG_USB_PD_DUAL_ROLE
@ -150,7 +150,10 @@ int ncp15wb_calculate_temp(uint16_t adc);
#define CONFIG_USB_PD_TCPM_STUB
#define CONFIG_SHA256
#define CONFIG_SW_CRC
#ifdef TEST_USB_PD_GIVEBACK
#define CONFIG_USB_PD_GIVE_BACK
#endif
#endif /* TEST_USB_PD || TEST_USB_PD_GIVEBACK */
#ifdef TEST_CHARGE_MANAGER
#define CONFIG_CHARGE_MANAGER

View File

@ -27,6 +27,8 @@ struct pd_port_t {
int partner_polarity;
} pd_port[CONFIG_USB_PD_PORT_COUNT];
static int give_back_called;
/* Mock functions */
int pd_adc_read(int port, int cc)
@ -193,9 +195,37 @@ static void unplug(int port)
usleep(30 * MSEC);
}
void pd_snk_give_back(int port, uint32_t * const ma, uint32_t * const mv)
{
if (*ma == 3000)
give_back_called = 1;
}
static void simulate_ps_rdy(int port)
{
uint16_t header = PD_HEADER(PD_CTRL_PS_RDY, PD_ROLE_SOURCE,
PD_ROLE_DFP, pd_port[port].msg_rx_id,
0);
simulate_rx_msg(port, header, 0, NULL);
}
static void simulate_goto_min(int port)
{
uint16_t header = PD_HEADER(PD_CTRL_GOTO_MIN, PD_ROLE_SOURCE,
PD_ROLE_DFP, pd_port[port].msg_rx_id, 0);
simulate_rx_msg(port, header, 0, NULL);
}
static int test_request_with_wait_and_contract(void)
{
#ifdef CONFIG_USB_PD_GIVE_BACK
uint32_t expected_rdo =
RDO_FIXED(2, 3000, PD_MIN_CURRENT_MA, RDO_GIVE_BACK);
#else
uint32_t expected_rdo = RDO_FIXED(2, 3000, 3000, 0);
#endif
uint8_t port = PORT0;
plug_in_source(port, 0);
@ -310,6 +340,34 @@ static int test_request_with_wait_and_contract(void)
task_wait_event(30 * MSEC);
TEST_ASSERT(verify_goodcrc(0, PD_ROLE_SINK, pd_port[port].msg_rx_id));
task_wake(PD_PORT_TO_TASK_ID(port));
task_wait_event(30 * MSEC);
inc_rx_id(port);
/* We're in SNK_TRANSITION. Send ps_rdy */
simulate_ps_rdy(port);
task_wait_event(30 * MSEC);
TEST_ASSERT(verify_goodcrc(0, PD_ROLE_SINK, pd_port[port].msg_rx_id));
task_wake(PD_PORT_TO_TASK_ID(port));
task_wait_event(30 * MSEC);
inc_rx_id(port);
/* We're in SNK_READY. Send goto_min */
simulate_goto_min(port);
task_wait_event(30 * MSEC);
TEST_ASSERT(verify_goodcrc(0, PD_ROLE_SINK, pd_port[port].msg_rx_id));
task_wake(PD_PORT_TO_TASK_ID(port));
task_wait_event(30 * MSEC);
inc_rx_id(port);
#ifdef CONFIG_USB_PD_GIVE_BACK
TEST_ASSERT(give_back_called);
#else
TEST_ASSERT(!give_back_called);
#endif
/* We're done */
unplug(port);
@ -318,7 +376,12 @@ static int test_request_with_wait_and_contract(void)
static int test_request_with_wait(void)
{
#ifdef CONFIG_USB_PD_GIVE_BACK
uint32_t expected_rdo = RDO_FIXED(1, 900, PD_MIN_CURRENT_MA,
RDO_CAP_MISMATCH | RDO_GIVE_BACK);
#else
uint32_t expected_rdo = RDO_FIXED(1, 900, 900, RDO_CAP_MISMATCH);
#endif
uint8_t port = PORT0;
plug_in_source(port, 0);
@ -401,7 +464,12 @@ static int test_request_with_wait(void)
static int test_request_with_reject(void)
{
#ifdef CONFIG_USB_PD_GIVE_BACK
uint32_t expected_rdo = RDO_FIXED(1, 900, PD_MIN_CURRENT_MA,
RDO_CAP_MISMATCH | RDO_GIVE_BACK);
#else
uint32_t expected_rdo = RDO_FIXED(1, 900, 900, RDO_CAP_MISMATCH);
#endif
uint8_t port = PORT0;
plug_in_source(port, 0);
@ -474,7 +542,12 @@ static int test_request_with_reject(void)
static int test_request(void)
{
#ifdef CONFIG_USB_PD_GIVE_BACK
uint32_t expected_rdo = RDO_FIXED(1, 900, PD_MIN_CURRENT_MA,
RDO_CAP_MISMATCH | RDO_GIVE_BACK);
#else
uint32_t expected_rdo = RDO_FIXED(1, 900, 900, RDO_CAP_MISMATCH);
#endif
uint8_t port = PORT0;
plug_in_source(port, 0);
@ -562,6 +635,5 @@ void run_test(void)
RUN_TEST(test_request_with_wait);
RUN_TEST(test_request_with_wait_and_contract);
RUN_TEST(test_request_with_reject);
test_print_result();
}

View File

@ -0,0 +1 @@
usb_pd.tasklist