diff options
Diffstat (limited to 'common/dps.c')
-rw-r--r-- | common/dps.c | 142 |
1 files changed, 93 insertions, 49 deletions
diff --git a/common/dps.c b/common/dps.c index 3af25e6280..13f551a95d 100644 --- a/common/dps.c +++ b/common/dps.c @@ -1,4 +1,4 @@ -/* Copyright 2021 The Chromium OS Authors. All rights reserved. +/* Copyright 2021 The ChromiumOS Authors * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * @@ -7,15 +7,14 @@ #include <stdint.h> -#include "adc.h" #include "dps.h" #include "atomic.h" #include "battery.h" +#include "common.h" #include "console.h" #include "charger.h" #include "charge_manager.h" #include "charge_state.h" -#include "charge_state_v2.h" #include "ec_commands.h" #include "math_util.h" #include "task.h" @@ -23,8 +22,6 @@ #include "usb_common.h" #include "usb_pd.h" #include "util.h" -#include "usb_pe_sm.h" - #define K_MORE_PWR 96 #define K_LESS_PWR 93 @@ -33,17 +30,16 @@ #define T_REQUEST_STABLE_TIME (10 * SECOND) #define T_NEXT_CHECK_TIME (5 * SECOND) -#define DPS_FLAG_DISABLED BIT(0) -#define DPS_FLAG_NO_SRCCAP BIT(1) -#define DPS_FLAG_WAITING BIT(2) -#define DPS_FLAG_SAMPLED BIT(3) -#define DPS_FLAG_NEED_MORE_PWR BIT(4) +#define DPS_FLAG_DISABLED BIT(0) +#define DPS_FLAG_NO_SRCCAP BIT(1) +#define DPS_FLAG_WAITING BIT(2) +#define DPS_FLAG_SAMPLED BIT(3) +#define DPS_FLAG_NEED_MORE_PWR BIT(4) -#define DPS_FLAG_STOP_EVENTS (DPS_FLAG_DISABLED | \ - DPS_FLAG_NO_SRCCAP) -#define DPS_FLAG_ALL GENMASK(31, 0) +#define DPS_FLAG_STOP_EVENTS (DPS_FLAG_DISABLED | DPS_FLAG_NO_SRCCAP) +#define DPS_FLAG_ALL GENMASK(31, 0) -#define MAX_MOVING_AVG_WINDOW 5 +#define MAX_MOVING_AVG_WINDOW 5 BUILD_ASSERT(K_MORE_PWR > K_LESS_PWR && 100 >= K_MORE_PWR && 100 >= K_LESS_PWR); @@ -71,6 +67,11 @@ __overridable struct dps_config_t dps_config = { .is_more_efficient = NULL, }; +__test_only struct dps_config_t *dps_get_config(void) +{ + return &dps_config; +} + int dps_get_dynamic_voltage(void) { return dynamic_mv; @@ -86,14 +87,15 @@ bool dps_is_enabled(void) return is_enabled; } -static void dps_enable(bool en) +test_export_static void dps_enable(bool en) { bool prev_en = is_enabled; is_enabled = en; - if (is_enabled && !prev_en) + if (is_enabled && !prev_en) { task_wake(TASK_ID_DPS); + } if (!is_enabled) { /* issue a new PD request for a default voltage */ @@ -126,22 +128,24 @@ static void dps_reset(void) /* * DPS initialization. */ -static void dps_init(void) +test_export_static int dps_init(void) { + int rc = EC_SUCCESS; + dps_reset(); if (dps_config.k_window > MAX_MOVING_AVG_WINDOW) { - dps_config.k_window = MAX_MOVING_AVG_WINDOW; CPRINTS("ERR:WIN"); + rc = EC_ERROR_INVALID_CONFIG; } - if (dps_config.k_less_pwr > 100 || - dps_config.k_more_pwr > 100 || + if (dps_config.k_less_pwr > 100 || dps_config.k_more_pwr > 100 || dps_config.k_more_pwr <= dps_config.k_less_pwr) { - dps_config.k_less_pwr = K_LESS_PWR; - dps_config.k_more_pwr = K_MORE_PWR; CPRINTS("ERR:COEF"); + rc = EC_ERROR_INVALID_CONFIG; } + + return rc; } static bool is_near_limit(int val, int limit) @@ -197,6 +201,26 @@ static int get_desired_input_power(int *vbus, int *input_current) return (*vbus) * (*input_current) / 1000; } +static int get_battery_target_voltage(int *target_mv) +{ + int charger_id = charge_get_active_chg_chip(); + int error = charger_get_voltage(charger_id, target_mv); + + if (!error) { + return EC_SUCCESS; + } + if (error != EC_ERROR_UNIMPLEMENTED) { + CPRINTS("Failed to get voltage for charge port %d: %d", + charger_id, error); + return error; + } + /* + * Fall back to battery design voltage if charger output voltage + * is not available. + */ + return battery_design_voltage(target_mv); +} + /* * Get the most efficient PDO voltage for the battery of the charging port * @@ -224,7 +248,7 @@ int get_efficient_voltage(void) if (!input_pwr) return 0; - if (battery_design_voltage(&batt_mv)) + if (get_battery_target_voltage(&batt_mv)) return 0; batt_pwr = batt->current * batt->voltage / 1000; @@ -258,16 +282,16 @@ struct pdo_candidate { }; #define UPDATE_CANDIDATE(new_port, new_mv, new_mw) \ - do { \ - cand->port = new_port; \ - cand->mv = new_mv; \ - cand->mw = new_mw; \ + do { \ + cand->port = new_port; \ + cand->mv = new_mv; \ + cand->mw = new_mw; \ } while (0) -#define CLEAR_AND_RETURN() \ - do { \ +#define CLEAR_AND_RETURN() \ + do { \ moving_avg_count = 0; \ - return false; \ + return false; \ } while (0) /* @@ -276,7 +300,7 @@ struct pdo_candidate { * @param struct pdo_candidate: The candidate PDO. (Return value) * @return true if a new power request, or false otherwise. */ -static bool has_new_power_request(struct pdo_candidate *cand) +__maybe_unused static bool has_new_power_request(struct pdo_candidate *cand) { int vbus, input_curr, input_pwr; int input_pwr_avg = 0, input_curr_avg = 0; @@ -305,7 +329,7 @@ static bool has_new_power_request(struct pdo_candidate *cand) if (!req_mv) CLEAR_AND_RETURN(); - if (battery_design_voltage(&batt_mv)) + if (get_battery_target_voltage(&batt_mv)) CLEAR_AND_RETURN(); /* if last sample is not the same as the current one, reset counting. */ @@ -360,7 +384,7 @@ static bool has_new_power_request(struct pdo_candidate *cand) input_curr, input_pwr_avg, input_curr_avg); for (int i = 0; i < board_get_usb_pd_port_count(); ++i) { - const uint32_t * const src_caps = pd_get_src_caps(i); + const uint32_t *const src_caps = pd_get_src_caps(i); /* If the port is not SNK, skip evaluating this port. */ if (pd_get_power_role(i) != PD_ROLE_SINK) @@ -380,7 +404,7 @@ static bool has_new_power_request(struct pdo_candidate *cand) if (mv > max_mv) continue; - mw = ma * mv / 1000; + mw = MIN(ma, PD_MAX_CURRENT_MA) * mv / 1000; efficient = is_more_efficient(mv, cand->mv, batt_mv, batt_pwr, input_pwr_avg); @@ -419,7 +443,6 @@ static bool has_new_power_request(struct pdo_candidate *cand) } } - /* * if the candidate is the same as the current one, pick * the one at active charge port. @@ -436,7 +459,7 @@ static bool has_new_power_request(struct pdo_candidate *cand) return (cand->mv != req_mv); } -static bool has_srccap(void) +__maybe_unused static bool has_srccap(void) { for (int i = 0; i < board_get_usb_pd_port_count(); ++i) { if (pd_is_connected(i) && @@ -454,14 +477,20 @@ void dps_update_stabilized_time(int port) void dps_task(void *u) { - struct pdo_candidate last_cand = {CHARGE_PORT_NONE, 0, 0}; + struct pdo_candidate last_cand = { CHARGE_PORT_NONE, 0, 0 }; int sample_count = 0; + int rv; + + rv = dps_init(); + if (rv) { + CPRINTS("ERR:INIT%d", rv); + return; + } - dps_init(); update_timeout(dps_config.t_check); while (1) { - struct pdo_candidate curr_cand = {CHARGE_PORT_NONE, 0, 0}; + struct pdo_candidate curr_cand = { CHARGE_PORT_NONE, 0, 0 }; timestamp_t now; now = get_time(); @@ -505,8 +534,7 @@ void dps_task(void *u) if (sample_count == dps_config.k_sample) { dynamic_mv = curr_cand.mv; dps_port = curr_cand.port; - pd_dpm_request(dps_port, - DPM_REQUEST_NEW_POWER_LEVEL); + pd_dpm_request(dps_port, DPM_REQUEST_NEW_POWER_LEVEL); sample_count = 0; flag &= ~(DPS_FLAG_SAMPLED | DPS_FLAG_NEED_MORE_PWR); } @@ -519,7 +547,7 @@ void dps_task(void *u) } } -static int command_dps(int argc, char **argv) +static int command_dps(int argc, const char **argv) { int port = charge_manager_get_active_charge_port(); int input_pwr, vbus, input_curr; @@ -545,7 +573,7 @@ static int command_dps(int argc, char **argv) return EC_SUCCESS; } - battery_design_voltage(&batt_mv); + get_battery_target_voltage(&batt_mv); input_pwr = get_desired_input_power(&vbus, &input_curr); if (!(flag & DPS_FLAG_NO_SRCCAP)) { last_mv = pd_get_requested_voltage(port); @@ -557,10 +585,8 @@ static int command_dps(int argc, char **argv) "Efficient: %dmV\n" "Batt: %dmv\n" "PDMaxMV: %dmV\n", - port, last_mv, last_ma, - vbus, input_curr, input_pwr, - get_efficient_voltage(), - batt_mv, + port, last_mv, last_ma, vbus, input_curr, input_pwr, + get_efficient_voltage(), batt_mv, pd_get_max_voltage()); return EC_SUCCESS; } @@ -657,6 +683,24 @@ static enum ec_status hc_usb_pd_dps_control(struct host_cmd_handler_args *args) dps_enable(p->enable); return EC_RES_SUCCESS; } -DECLARE_HOST_COMMAND(EC_CMD_USB_PD_DPS_CONTROL, - hc_usb_pd_dps_control, +DECLARE_HOST_COMMAND(EC_CMD_USB_PD_DPS_CONTROL, hc_usb_pd_dps_control, EC_VER_MASK(0)); + +#ifdef TEST_BUILD +__test_only bool dps_is_fake_enabled(void) +{ + return fake_enabled; +} +__test_only int dps_get_fake_mv(void) +{ + return fake_mv; +} +__test_only int dps_get_fake_ma(void) +{ + return fake_ma; +} +__test_only int *dps_get_debug_level(void) +{ + return &debug_level; +} +#endif /* TEST_BUILD */ |