summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/host/board.h3
-rw-r--r--board/kevin/board.h4
-rw-r--r--board/kevin/usb_pd_policy.c10
-rw-r--r--common/usb_pd_policy.c30
-rw-r--r--common/usb_pd_protocol.c15
-rw-r--r--include/config.h3
-rw-r--r--include/usb_pd.h9
-rw-r--r--test/build.mk2
-rw-r--r--test/test_config.h5
-rw-r--r--test/usb_pd.c74
l---------test/usb_pd_giveback.tasklist1
11 files changed, 152 insertions, 4 deletions
diff --git a/board/host/board.h b/board/host/board.h
index a5b6a5dc20..aa82d600d4 100644
--- a/board/host/board.h
+++ b/board/host/board.h
@@ -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 */
diff --git a/board/kevin/board.h b/board/kevin/board.h
index 304de3da1e..2985609b75 100644
--- a/board/kevin/board.h
+++ b/board/kevin/board.h
@@ -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 */
diff --git a/board/kevin/usb_pd_policy.c b/board/kevin/usb_pd_policy.c
index dbd8bceec3..deef42c250 100644
--- a/board/kevin/usb_pd_policy.c
+++ b/board/kevin/usb_pd_policy.c
@@ -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;
diff --git a/common/usb_pd_policy.c b/common/usb_pd_policy.c
index fe204b9301..97e7718bf6 100644
--- a/common/usb_pd_policy.c
+++ b/common/usb_pd_policy.c
@@ -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;
}
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 28f7796240..ecd593e1e3 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -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) {
diff --git a/include/config.h b/include/config.h
index 27f7fbb789..dd1ab1167b 100644
--- a/include/config.h
+++ b/include/config.h
@@ -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
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 08eef75822..940424ecfa 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -904,6 +904,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.
*/
diff --git a/test/build.mk b/test/build.mk
index 19fa51f5b0..ae1304cf59 100644
--- a/test/build.mk
+++ b/test/build.mk
@@ -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
diff --git a/test/test_config.h b/test/test_config.h
index d2438c9612..fcad730c7f 100644
--- a/test/test_config.h
+++ b/test/test_config.h
@@ -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
diff --git a/test/usb_pd.c b/test/usb_pd.c
index 233714e3ad..d87a4c3960 100644
--- a/test/usb_pd.c
+++ b/test/usb_pd.c
@@ -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();
}
diff --git a/test/usb_pd_giveback.tasklist b/test/usb_pd_giveback.tasklist
new file mode 120000
index 0000000000..45cc6c8aa2
--- /dev/null
+++ b/test/usb_pd_giveback.tasklist
@@ -0,0 +1 @@
+usb_pd.tasklist \ No newline at end of file