diff options
-rw-r--r-- | common/usb_pd_dual_role.c | 40 | ||||
-rw-r--r-- | include/usb_common.h | 4 | ||||
-rw-r--r-- | test/usb_common_test.c | 129 |
3 files changed, 155 insertions, 18 deletions
diff --git a/common/usb_pd_dual_role.c b/common/usb_pd_dual_role.c index 61bce77129..2ad0b99125 100644 --- a/common/usb_pd_dual_role.c +++ b/common/usb_pd_dual_role.c @@ -157,32 +157,40 @@ int pd_find_pdo_index(uint32_t src_cap_cnt, const uint32_t * const src_caps, void pd_extract_pdo_power(uint32_t pdo, uint32_t *ma, uint32_t *max_mv, uint32_t *min_mv) { - uint32_t max_ma, uw; - - if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_AUGMENTED) { - max_ma = 50 * (pdo & GENMASK(6, 0)); - *min_mv = 100 * ((pdo & GENMASK(15, 8)) >> 8); - *max_mv = 100 * ((pdo & GENMASK(24, 17)) >> 17); - max_ma = MIN(max_ma, PD_MAX_POWER_MW * 1000 / *min_mv); - *ma = MIN(max_ma, PD_MAX_CURRENT_MA); - return; + int max_ma, mw; + + if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_FIXED) { + *max_mv = PDO_FIXED_VOLTAGE(pdo); + *min_mv = *max_mv; + } else if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_AUGMENTED) { + *max_mv = PDO_AUG_MAX_VOLTAGE(pdo); + *min_mv = PDO_AUG_MIN_VOLTAGE(pdo); + } else if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_VARIABLE) { + *max_mv = PDO_VAR_MAX_VOLTAGE(pdo); + *min_mv = PDO_VAR_MIN_VOLTAGE(pdo); + } else { + *max_mv = PDO_BATT_MAX_VOLTAGE(pdo); + *min_mv = PDO_BATT_MIN_VOLTAGE(pdo); } - *max_mv = ((pdo >> 10) & 0x3FF) * 50; if (*max_mv == 0) { *ma = 0; *min_mv = 0; return; } - if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_BATTERY) { - uw = 250000 * (pdo & 0x3FF); - max_ma = 1000 * MIN(1000 * uw, PD_MAX_POWER_MW) / *max_mv; + + if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_FIXED) { + max_ma = PDO_FIXED_CURRENT(pdo); + } else if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_AUGMENTED) { + max_ma = PDO_AUG_MAX_CURRENT(pdo); + } else if ((pdo & PDO_TYPE_MASK) == PDO_TYPE_VARIABLE) { + max_ma = PDO_VAR_MAX_CURRENT(pdo); } else { - max_ma = 10 * (pdo & 0x3FF); - max_ma = MIN(max_ma, PD_MAX_POWER_MW * 1000 / *max_mv); + mw = PDO_BATT_MAX_POWER(pdo); + max_ma = 1000 * mw / *min_mv; } + max_ma = MIN(max_ma, PD_MAX_POWER_MW * 1000 / *min_mv); *ma = MIN(max_ma, PD_MAX_CURRENT_MA); - *min_mv = *max_mv; } void pd_build_request(int32_t vpd_vdo, uint32_t *rdo, uint32_t *ma, diff --git a/include/usb_common.h b/include/usb_common.h index 57c2e1d870..fc385eacf8 100644 --- a/include/usb_common.h +++ b/include/usb_common.h @@ -134,8 +134,8 @@ int pd_find_pdo_index(uint32_t src_cap_cnt, const uint32_t * const src_caps, * * @param pdo raw pdo to extract * @param ma current of the PDO (output) - * @param mv voltage of the PDO, or max_mv of the Augmented PDO (output) - * @param mv voltage of the PDO, or min_mv of the Augmented PDO (output) + * @param max_mv maximum voltage of the PDO (output) + * @param min_mv minimum voltage of the PDO (output) */ void pd_extract_pdo_power(uint32_t pdo, uint32_t *ma, uint32_t *max_mv, uint32_t *min_mv); diff --git a/test/usb_common_test.c b/test/usb_common_test.c index c7cec27640..620e061f74 100644 --- a/test/usb_common_test.c +++ b/test/usb_common_test.c @@ -66,9 +66,138 @@ int test_pd_get_cc_state(void) return EC_SUCCESS; } +/* + * From USB Power Delivery Specification Revision 3.0, Version 2.0 + * Table 6-7 Power Data Object + */ +#define MAKE_FIXED(v, c) (0 << 30 | (v / 50) << 10 | (c / 10)) +#define MAKE_BATT(v_max, v_min, p) \ + (1 << 30 | (v_max / 50) << 20 | (v_min / 50) << 10 | (p / 250)) +#define MAKE_VAR(v_max, v_min, c) \ + (2 << 30 | (v_max / 50) << 20 | (v_min / 50) << 10 | (c / 10)) +#define MAKE_AUG(v_max, v_min, c) \ + (3 << 30 | (v_max / 100) << 17 | (v_min / 100) << 8 | (c / 50)) + +/* + * Tests various cases for pd_extract_pdo_power. It takes a very high voltage to + * exceed PD_MAX_POWER_MW without also exceeding PD_MAX_CURRENT_MA, so those + * tests are not particularly realistic. + */ +int test_pd_extract_pdo_power(void) +{ + uint32_t ma; + uint32_t max_mv; + uint32_t min_mv; + + pd_extract_pdo_power(MAKE_FIXED(/*v=*/5000, /*c=*/3000), &ma, &max_mv, + &min_mv); + TEST_EQ(max_mv, 5000, "%d"); + TEST_EQ(min_mv, 5000, "%d"); + TEST_EQ(ma, 3000, "%d"); + pd_extract_pdo_power(MAKE_FIXED(/*v=*/20000, /*c=*/2600), &ma, &max_mv, + &min_mv); + TEST_EQ(max_mv, 20000, "%d"); + TEST_EQ(min_mv, 20000, "%d"); + TEST_EQ(ma, 2600, "%d"); + pd_extract_pdo_power(MAKE_FIXED(/*v=*/20000, /*c=*/4000), &ma, &max_mv, + &min_mv); + TEST_EQ(max_mv, 20000, "%d"); + TEST_EQ(min_mv, 20000, "%d"); + TEST_EQ(ma, 3000, "%d"); /* Capped at PD_MAX_CURRENT_MA */ + pd_extract_pdo_power(MAKE_FIXED(/*v=*/10000, /*c=*/4000), &ma, &max_mv, + &min_mv); + TEST_EQ(max_mv, 10000, "%d"); + TEST_EQ(min_mv, 10000, "%d"); + TEST_EQ(ma, 3000, "%d"); /* Capped at PD_MAX_CURRENT_MA */ + pd_extract_pdo_power(MAKE_FIXED(/*v=*/21000, /*c=*/4000), &ma, &max_mv, + &min_mv); + TEST_EQ(max_mv, 21000, "%d"); + TEST_EQ(min_mv, 21000, "%d"); + TEST_EQ(ma, 2857, "%d"); /* Capped at PD_MAX_POWER_MW */ + + pd_extract_pdo_power(MAKE_BATT(/*v_max=*/5700, /*v_min=*/3300, + /*p=*/7000), + &ma, &max_mv, &min_mv); + TEST_EQ(max_mv, 5700, "%d"); + TEST_EQ(min_mv, 3300, "%d"); + TEST_EQ(ma, 2121, "%d"); /* 3300mV * 2121mA ~= 7000mW */ + pd_extract_pdo_power(MAKE_BATT(/*v_max=*/3300, /*v_min=*/2700, + /*p=*/12000), + &ma, &max_mv, &min_mv); + TEST_EQ(max_mv, 3300, "%d"); + TEST_EQ(min_mv, 2700, "%d"); + TEST_EQ(ma, 3000, "%d"); /* Capped at PD_MAX_CURRENT_MA */ + + pd_extract_pdo_power(MAKE_BATT(/*v_max=*/25000, /*v_min=*/21000, + /*p=*/61000), + &ma, &max_mv, &min_mv); + TEST_EQ(max_mv, 25000, "%d"); + TEST_EQ(min_mv, 21000, "%d"); + TEST_EQ(ma, 2857, "%d"); /* Capped at PD_MAX_POWER_MW */ + + pd_extract_pdo_power(MAKE_VAR(/*v_max=*/5000, /*v_min=*/3300, + /*c=*/3000), + &ma, &max_mv, &min_mv); + TEST_EQ(max_mv, 5000, "%d"); + TEST_EQ(min_mv, 3300, "%d"); + TEST_EQ(ma, 3000, "%d"); + pd_extract_pdo_power(MAKE_VAR(/*v_max=*/20000, /*v_min=*/5000, + /*c=*/2600), + &ma, &max_mv, &min_mv); + TEST_EQ(max_mv, 20000, "%d"); + TEST_EQ(min_mv, 5000, "%d"); + TEST_EQ(ma, 2600, "%d"); + pd_extract_pdo_power(MAKE_VAR(/*v_max=*/20000, /*v_min=*/5000, + /*c=*/4000), + &ma, &max_mv, &min_mv); + TEST_EQ(max_mv, 20000, "%d"); + TEST_EQ(min_mv, 5000, "%d"); + TEST_EQ(ma, 3000, "%d"); /* Capped at PD_MAX_CURRENT_MA */ + pd_extract_pdo_power(MAKE_VAR(/*v_max=*/10000, /*v_min=*/3300, + /*c=*/4000), + &ma, &max_mv, &min_mv); + TEST_EQ(max_mv, 10000, "%d"); + TEST_EQ(min_mv, 3300, "%d"); + TEST_EQ(ma, 3000, "%d"); /* Capped at PD_MAX_CURRENT_MA */ + pd_extract_pdo_power(MAKE_VAR(/*v_max=*/22000, /*v_min=*/21000, + /*c=*/4000), + &ma, &max_mv, &min_mv); + TEST_EQ(max_mv, 22000, "%d"); + TEST_EQ(min_mv, 21000, "%d"); + TEST_EQ(ma, 2857, "%d"); /* Capped at PD_MAX_POWER_MW */ + + pd_extract_pdo_power(MAKE_AUG(/*v_max=*/5000, /*v_min=*/3300, + /*c=*/3000), + &ma, &max_mv, &min_mv); + TEST_EQ(max_mv, 5000, "%d"); + TEST_EQ(min_mv, 3300, "%d"); + TEST_EQ(ma, 3000, "%d"); + pd_extract_pdo_power(MAKE_AUG(/*v_max=*/20000, /*v_min=*/3300, + /*c=*/2600), + &ma, &max_mv, &min_mv); + TEST_EQ(max_mv, 20000, "%d"); + TEST_EQ(min_mv, 3300, "%d"); + TEST_EQ(ma, 2600, "%d"); + pd_extract_pdo_power(MAKE_AUG(/*v_max=*/10000, /*v_min=*/3300, + /*c=*/4000), + &ma, &max_mv, &min_mv); + TEST_EQ(max_mv, 10000, "%d"); + TEST_EQ(min_mv, 3300, "%d"); + TEST_EQ(ma, 3000, "%d"); /* Capped at PD_MAX_CURRENT_MA */ + pd_extract_pdo_power(MAKE_AUG(/*v_max=*/22000, /*v_min=*/21000, + /*c=*/4000), + &ma, &max_mv, &min_mv); + TEST_EQ(max_mv, 22000, "%d"); + TEST_EQ(min_mv, 21000, "%d"); + TEST_EQ(ma, 2857, "%d"); /* Capped at PD_MAX_POWER_MW */ + + return EC_SUCCESS; +} + void run_test(int argc, char **argv) { RUN_TEST(test_pd_get_cc_state); + RUN_TEST(test_pd_extract_pdo_power); test_print_result(); } |