diff options
Diffstat (limited to 'board/honeybuns/usb_pd_policy.c')
-rw-r--r-- | board/honeybuns/usb_pd_policy.c | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/board/honeybuns/usb_pd_policy.c b/board/honeybuns/usb_pd_policy.c new file mode 100644 index 0000000000..7e45a0cc87 --- /dev/null +++ b/board/honeybuns/usb_pd_policy.c @@ -0,0 +1,243 @@ +/* Copyright 2015 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "charger.h" +#include "common.h" +#include "console.h" +#include "gpio.h" +#include "hooks.h" +#include "registers.h" +#include "system.h" +#include "task.h" +#include "timer.h" +#include "util.h" +#include "usb_pd.h" + + +#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) +#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) + +#define PDO_FIXED_FLAGS (PDO_FIXED_EXTERNAL | PDO_FIXED_DUAL_ROLE | \ + PDO_FIXED_DATA_SWAP) + +const uint32_t pd_src_pdo[] = { + PDO_FIXED(5000, 3000, PDO_FIXED_FLAGS), + PDO_FIXED(12000, 3000, PDO_FIXED_FLAGS), + PDO_FIXED(20000, 3000, PDO_FIXED_FLAGS), +}; +const int pd_src_pdo_cnt = ARRAY_SIZE(pd_src_pdo); + +const uint32_t pd_snk_pdo[] = { + PDO_FIXED(5000, 500, PDO_FIXED_FLAGS), +}; +const int pd_snk_pdo_cnt = ARRAY_SIZE(pd_snk_pdo); + +/* Holds valid object position (opos) for entered mode */ +static int alt_mode[PD_AMODE_COUNT]; + +void pd_set_input_current_limit(int port, uint32_t max_ma, + uint32_t supply_voltage) +{ + +} + + +int pd_is_valid_input_voltage(int mv) +{ + /* Any voltage less than the max is allowed */ + return 1; +} + +int pd_check_requested_voltage(uint32_t rdo) +{ + int max_ma = rdo & 0x3FF; + int op_ma = (rdo >> 10) & 0x3FF; + int idx = rdo >> 28; + uint32_t pdo; + uint32_t pdo_ma; + + if (!idx || idx > pd_src_pdo_cnt) + return EC_ERROR_INVAL; /* Invalid index */ + + /* check current ... */ + pdo = pd_src_pdo[idx - 1]; + pdo_ma = (pdo & 0x3ff); + if (op_ma > pdo_ma) + return EC_ERROR_INVAL; /* too much op current */ + if (max_ma > pdo_ma) + return EC_ERROR_INVAL; /* too much max current */ + + CPRINTF("Requested %d V %d mA (for %d/%d mA)\n", + ((pdo >> 10) & 0x3ff) * 50, (pdo & 0x3ff) * 10, + ((rdo >> 10) & 0x3ff) * 10, (rdo & 0x3ff) * 10); + + return EC_SUCCESS; +} + +void pd_transition_voltage(int idx) +{ + /* No-operation: we are always 5V */ +} + +int pd_set_power_supply_ready(int port) +{ + /* provide VBUS */ + gpio_set_level(GPIO_PPVAR_VBUS_EN, 1); + return EC_SUCCESS; /* we are ready */ +} + +void pd_power_supply_reset(int port) +{ + /* Kill VBUS */ + gpio_set_level(GPIO_PPVAR_VBUS_EN, 0); +} + +int pd_board_checks(void) +{ + return EC_SUCCESS; +} + +int pd_check_power_swap(int port) +{ + /* Always allow power swap */ + return 1; +} + +int pd_check_data_swap(int port, int data_role) +{ + /* Always allow data swap */ + return 1; +} + +void pd_execute_data_swap(int port, int data_role) +{ + /* Do nothing */ +} + +void pd_check_pr_role(int port, int pr_role, int partner_pr_swap) +{ +} + +void pd_check_dr_role(int port, int dr_role, int partner_dr_swap) +{ +} + +int pd_alt_mode(int port, uint16_t svid) +{ + if (svid == USB_SID_DISPLAYPORT) + return alt_mode[PD_AMODE_DISPLAYPORT]; + else if (svid == USB_VID_GOOGLE) + return alt_mode[PD_AMODE_GOOGLE]; + return 0; +} + + +/* ----------------- Vendor Defined Messages ------------------ */ +/* TODO () The VDM section needs to be updated for honeybuns */ +const struct svdm_response svdm_rsp = { + .identity = NULL, + .svids = NULL, + .modes = NULL, +}; + +int pd_custom_vdm(int port, int cnt, uint32_t *payload, + uint32_t **rpayload) +{ + int cmd = PD_VDO_CMD(payload[0]); + uint16_t dev_id = 0; + + /* make sure we have some payload */ + if (cnt == 0) + return 0; + + switch (cmd) { + case VDO_CMD_VERSION: + /* guarantee last byte of payload is null character */ + *(payload + cnt - 1) = 0; + CPRINTF("version: %s\n", (char *)(payload+1)); + break; + case VDO_CMD_READ_INFO: + case VDO_CMD_SEND_INFO: + /* if last word is present, it contains lots of info */ + if (cnt == 7) { + dev_id = VDO_INFO_HW_DEV_ID(payload[6]); + CPRINTF("DevId:%d.%d SW:%d RW:%d\n", + HW_DEV_ID_MAJ(dev_id), + HW_DEV_ID_MIN(dev_id), + VDO_INFO_SW_DBG_VER(payload[6]), + VDO_INFO_IS_RW(payload[6])); + } + /* copy hash */ + if (cnt >= 6) + pd_dev_store_rw_hash(port, dev_id, payload + 1, + SYSTEM_IMAGE_UNKNOWN); + + break; + } + + return 0; +} + +static int svdm_enter_dp_mode(int port, uint32_t mode_caps) +{ + /* Only enter mode if device is DFP_D capable */ + if (mode_caps & MODE_DP_SNK) { + CPRINTF("Entering mode w/ vdo = %08x\n", mode_caps); + return 0; + } + + return -1; +} + +static int dp_on; + +static int svdm_dp_status(int port, uint32_t *payload) +{ + payload[0] = VDO(USB_SID_DISPLAYPORT, 1, CMD_DP_STATUS); + payload[1] = VDO_DP_STATUS(0, /* HPD IRQ ... not applicable */ + 0, /* HPD level ... not applicable */ + 0, /* exit DP? ... no */ + 0, /* usb mode? ... no */ + 0, /* multi-function ... no */ + dp_on, + 0, /* power low? ... no */ + dp_on); + return 2; +}; + +static int svdm_dp_config(int port, uint32_t *payload) +{ + board_set_usb_mux(port, TYPEC_MUX_DP, pd_get_polarity(port)); + dp_on = 1; + payload[0] = VDO(USB_SID_DISPLAYPORT, 1, CMD_DP_CONFIG); + payload[1] = VDO_DP_CFG(MODE_DP_PIN_E, /* sink pins */ + MODE_DP_PIN_E, /* src pins */ + 1, /* DPv1.3 signaling */ + 2); /* UFP connected */ + return 2; +}; + +static int svdm_dp_attention(int port, uint32_t *payload) +{ + return 1; /* ack */ +} + +static void svdm_exit_dp_mode(int port) +{ + CPRINTF("Exiting mode\n"); + /* return to safe config */ +} + +const struct svdm_amode_fx supported_modes[] = { + { + .svid = USB_SID_DISPLAYPORT, + .enter = &svdm_enter_dp_mode, + .status = &svdm_dp_status, + .config = &svdm_dp_config, + .attention = &svdm_dp_attention, + .exit = &svdm_exit_dp_mode, + }, +}; +const int supported_modes_cnt = ARRAY_SIZE(supported_modes); |