linux-stable/include/linux/usb/pd.h

537 lines
16 KiB
C
Raw Normal View History

treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 157 Based on 3 normalized pattern(s): this program is free software you can redistribute it and or modify it under the terms of the gnu general public license as published by the free software foundation either version 2 of the license or at your option any later version this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details this program is free software you can redistribute it and or modify it under the terms of the gnu general public license as published by the free software foundation either version 2 of the license or at your option any later version [author] [kishon] [vijay] [abraham] [i] [kishon]@[ti] [com] this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details this program is free software you can redistribute it and or modify it under the terms of the gnu general public license as published by the free software foundation either version 2 of the license or at your option any later version [author] [graeme] [gregory] [gg]@[slimlogic] [co] [uk] [author] [kishon] [vijay] [abraham] [i] [kishon]@[ti] [com] [based] [on] [twl6030]_[usb] [c] [author] [hema] [hk] [hemahk]@[ti] [com] this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details extracted by the scancode license scanner the SPDX license identifier GPL-2.0-or-later has been chosen to replace the boilerplate/reference in 1105 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Allison Randal <allison@lohutok.net> Reviewed-by: Richard Fontana <rfontana@redhat.com> Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190527070033.202006027@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-05-27 06:55:06 +00:00
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright 2015-2017 Google, Inc
*/
#ifndef __LINUX_USB_PD_H
#define __LINUX_USB_PD_H
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/usb/typec.h>
/* USB PD Messages */
enum pd_ctrl_msg_type {
/* 0 Reserved */
PD_CTRL_GOOD_CRC = 1,
PD_CTRL_GOTO_MIN = 2,
PD_CTRL_ACCEPT = 3,
PD_CTRL_REJECT = 4,
PD_CTRL_PING = 5,
PD_CTRL_PS_RDY = 6,
PD_CTRL_GET_SOURCE_CAP = 7,
PD_CTRL_GET_SINK_CAP = 8,
PD_CTRL_DR_SWAP = 9,
PD_CTRL_PR_SWAP = 10,
PD_CTRL_VCONN_SWAP = 11,
PD_CTRL_WAIT = 12,
PD_CTRL_SOFT_RESET = 13,
/* 14-15 Reserved */
PD_CTRL_NOT_SUPP = 16,
PD_CTRL_GET_SOURCE_CAP_EXT = 17,
PD_CTRL_GET_STATUS = 18,
PD_CTRL_FR_SWAP = 19,
PD_CTRL_GET_PPS_STATUS = 20,
PD_CTRL_GET_COUNTRY_CODES = 21,
/* 22-31 Reserved */
};
enum pd_data_msg_type {
/* 0 Reserved */
PD_DATA_SOURCE_CAP = 1,
PD_DATA_REQUEST = 2,
PD_DATA_BIST = 3,
PD_DATA_SINK_CAP = 4,
PD_DATA_BATT_STATUS = 5,
PD_DATA_ALERT = 6,
PD_DATA_GET_COUNTRY_INFO = 7,
PD_DATA_ENTER_USB = 8,
/* 9-14 Reserved */
PD_DATA_VENDOR_DEF = 15,
/* 16-31 Reserved */
};
enum pd_ext_msg_type {
/* 0 Reserved */
PD_EXT_SOURCE_CAP_EXT = 1,
PD_EXT_STATUS = 2,
PD_EXT_GET_BATT_CAP = 3,
PD_EXT_GET_BATT_STATUS = 4,
PD_EXT_BATT_CAP = 5,
PD_EXT_GET_MANUFACTURER_INFO = 6,
PD_EXT_MANUFACTURER_INFO = 7,
PD_EXT_SECURITY_REQUEST = 8,
PD_EXT_SECURITY_RESPONSE = 9,
PD_EXT_FW_UPDATE_REQUEST = 10,
PD_EXT_FW_UPDATE_RESPONSE = 11,
PD_EXT_PPS_STATUS = 12,
PD_EXT_COUNTRY_INFO = 13,
PD_EXT_COUNTRY_CODES = 14,
/* 15-31 Reserved */
};
#define PD_REV10 0x0
#define PD_REV20 0x1
#define PD_REV30 0x2
#define PD_MAX_REV PD_REV30
#define PD_HEADER_EXT_HDR BIT(15)
#define PD_HEADER_CNT_SHIFT 12
#define PD_HEADER_CNT_MASK 0x7
#define PD_HEADER_ID_SHIFT 9
#define PD_HEADER_ID_MASK 0x7
#define PD_HEADER_PWR_ROLE BIT(8)
#define PD_HEADER_REV_SHIFT 6
#define PD_HEADER_REV_MASK 0x3
#define PD_HEADER_DATA_ROLE BIT(5)
#define PD_HEADER_TYPE_SHIFT 0
#define PD_HEADER_TYPE_MASK 0x1f
#define PD_HEADER(type, pwr, data, rev, id, cnt, ext_hdr) \
((((type) & PD_HEADER_TYPE_MASK) << PD_HEADER_TYPE_SHIFT) | \
((pwr) == TYPEC_SOURCE ? PD_HEADER_PWR_ROLE : 0) | \
((data) == TYPEC_HOST ? PD_HEADER_DATA_ROLE : 0) | \
(rev << PD_HEADER_REV_SHIFT) | \
(((id) & PD_HEADER_ID_MASK) << PD_HEADER_ID_SHIFT) | \
(((cnt) & PD_HEADER_CNT_MASK) << PD_HEADER_CNT_SHIFT) | \
((ext_hdr) ? PD_HEADER_EXT_HDR : 0))
#define PD_HEADER_LE(type, pwr, data, rev, id, cnt) \
cpu_to_le16(PD_HEADER((type), (pwr), (data), (rev), (id), (cnt), (0)))
static inline unsigned int pd_header_cnt(u16 header)
{
return (header >> PD_HEADER_CNT_SHIFT) & PD_HEADER_CNT_MASK;
}
static inline unsigned int pd_header_cnt_le(__le16 header)
{
return pd_header_cnt(le16_to_cpu(header));
}
static inline unsigned int pd_header_type(u16 header)
{
return (header >> PD_HEADER_TYPE_SHIFT) & PD_HEADER_TYPE_MASK;
}
static inline unsigned int pd_header_type_le(__le16 header)
{
return pd_header_type(le16_to_cpu(header));
}
static inline unsigned int pd_header_msgid(u16 header)
{
return (header >> PD_HEADER_ID_SHIFT) & PD_HEADER_ID_MASK;
}
static inline unsigned int pd_header_msgid_le(__le16 header)
{
return pd_header_msgid(le16_to_cpu(header));
}
static inline unsigned int pd_header_rev(u16 header)
{
return (header >> PD_HEADER_REV_SHIFT) & PD_HEADER_REV_MASK;
}
static inline unsigned int pd_header_rev_le(__le16 header)
{
return pd_header_rev(le16_to_cpu(header));
}
#define PD_EXT_HDR_CHUNKED BIT(15)
#define PD_EXT_HDR_CHUNK_NUM_SHIFT 11
#define PD_EXT_HDR_CHUNK_NUM_MASK 0xf
#define PD_EXT_HDR_REQ_CHUNK BIT(10)
#define PD_EXT_HDR_DATA_SIZE_SHIFT 0
#define PD_EXT_HDR_DATA_SIZE_MASK 0x1ff
#define PD_EXT_HDR(data_size, req_chunk, chunk_num, chunked) \
((((data_size) & PD_EXT_HDR_DATA_SIZE_MASK) << PD_EXT_HDR_DATA_SIZE_SHIFT) | \
((req_chunk) ? PD_EXT_HDR_REQ_CHUNK : 0) | \
(((chunk_num) & PD_EXT_HDR_CHUNK_NUM_MASK) << PD_EXT_HDR_CHUNK_NUM_SHIFT) | \
((chunked) ? PD_EXT_HDR_CHUNKED : 0))
#define PD_EXT_HDR_LE(data_size, req_chunk, chunk_num, chunked) \
cpu_to_le16(PD_EXT_HDR((data_size), (req_chunk), (chunk_num), (chunked)))
static inline unsigned int pd_ext_header_chunk_num(u16 ext_header)
{
return (ext_header >> PD_EXT_HDR_CHUNK_NUM_SHIFT) &
PD_EXT_HDR_CHUNK_NUM_MASK;
}
static inline unsigned int pd_ext_header_data_size(u16 ext_header)
{
return (ext_header >> PD_EXT_HDR_DATA_SIZE_SHIFT) &
PD_EXT_HDR_DATA_SIZE_MASK;
}
static inline unsigned int pd_ext_header_data_size_le(__le16 ext_header)
{
return pd_ext_header_data_size(le16_to_cpu(ext_header));
}
#define PD_MAX_PAYLOAD 7
#define PD_EXT_MAX_CHUNK_DATA 26
/**
* struct pd_chunked_ext_message_data - PD chunked extended message data as
* seen on wire
* @header: PD extended message header
* @data: PD extended message data
*/
struct pd_chunked_ext_message_data {
__le16 header;
u8 data[PD_EXT_MAX_CHUNK_DATA];
} __packed;
/**
* struct pd_message - PD message as seen on wire
* @header: PD message header
* @payload: PD message payload
* @ext_msg: PD message chunked extended message data
*/
struct pd_message {
__le16 header;
union {
__le32 payload[PD_MAX_PAYLOAD];
struct pd_chunked_ext_message_data ext_msg;
};
} __packed;
/* PDO: Power Data Object */
#define PDO_MAX_OBJECTS 7
enum pd_pdo_type {
PDO_TYPE_FIXED = 0,
PDO_TYPE_BATT = 1,
PDO_TYPE_VAR = 2,
PDO_TYPE_APDO = 3,
};
#define PDO_TYPE_SHIFT 30
#define PDO_TYPE_MASK 0x3
#define PDO_TYPE(t) ((t) << PDO_TYPE_SHIFT)
#define PDO_VOLT_MASK 0x3ff
#define PDO_CURR_MASK 0x3ff
#define PDO_PWR_MASK 0x3ff
usb: typec: tcpm: Add support for Sink Fast Role SWAP(FRS) PD 3.0 spec defines a new mechanism for power role swap called Fast role swap. This change enables TCPM to support FRS when acting as sink. Once the explicit contract is negotiated, sink port is expected to query the source port for sink caps to determine whether the source is FRS capable. Bits 23 & 24 of fixed pdo of the sink caps from the source, when set, indicates the current needed by the source when fast role swap is in progress(Implicit contract phasae). 0 indicates that the source does not support Fast Role Swap. Upon receiving the FRS signal from the source, TCPC(TCPM_FRS_EVENT) informs TCPM to start the Fast role swap sequence. 1. TCPM sends FRS PD message: FR_SWAP_SEND 2. If response is not received within the expiry of SenderResponseTimer, Error recovery is triggered.: FR_SWAP_SEND_TIMEOUT 3. Upon receipt of the accept message, TCPM waits for PSSourceOffTimer for PS_READY message from the partner: FR_SWAP_SNK_SRC_NEW_SINK_READY. TCPC is expected to autonomously turn on vbus once the FRS signal is received and vbus voltage falls below vsafe5v within tSrcFrSwap. This is different from traditional power role swap where the vbus sourcing is turned on by TCPM. 4. By this time, TCPC most likely would have started to source vbus, TCPM waits for tSrcFrSwap to see if the lower level TCPC driver signals TCPM_SOURCING_VBUS event: FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED. 5. When TCPC signals sourcing vbus, TCPM sends PS_READY msg and changes the CC pin from Rd to Rp. This is the end of fast role swap sequence and TCPM initiates the sequnce to negotiate explicit contract by transitioning into SRC_STARTUP after SwapSrcStart. The code is written based on the sequence described in "Figure 8-107: Dual-role Port in Sink to Source Fast Role Swap State Diagram" of USB Power Delivery Specification Revision 3.0, Version 1.2. Signed-off-by: Badhri Jagan Sridharan <badhri@google.com> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Link: https://lore.kernel.org/r/20201008061556.1402293-7-badhri@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2020-10-08 06:15:47 +00:00
#define PDO_FIXED_DUAL_ROLE BIT(29) /* Power role swap supported */
#define PDO_FIXED_SUSPEND BIT(28) /* USB Suspend supported (Source) */
#define PDO_FIXED_HIGHER_CAP BIT(28) /* Requires more than vSafe5V (Sink) */
#define PDO_FIXED_EXTPOWER BIT(27) /* Externally powered */
#define PDO_FIXED_USB_COMM BIT(26) /* USB communications capable */
#define PDO_FIXED_DATA_SWAP BIT(25) /* Data role swap supported */
#define PDO_FIXED_UNCHUNK_EXT BIT(24) /* Unchunked Extended Message supported (Source) */
usb: typec: tcpm: Add support for Sink Fast Role SWAP(FRS) PD 3.0 spec defines a new mechanism for power role swap called Fast role swap. This change enables TCPM to support FRS when acting as sink. Once the explicit contract is negotiated, sink port is expected to query the source port for sink caps to determine whether the source is FRS capable. Bits 23 & 24 of fixed pdo of the sink caps from the source, when set, indicates the current needed by the source when fast role swap is in progress(Implicit contract phasae). 0 indicates that the source does not support Fast Role Swap. Upon receiving the FRS signal from the source, TCPC(TCPM_FRS_EVENT) informs TCPM to start the Fast role swap sequence. 1. TCPM sends FRS PD message: FR_SWAP_SEND 2. If response is not received within the expiry of SenderResponseTimer, Error recovery is triggered.: FR_SWAP_SEND_TIMEOUT 3. Upon receipt of the accept message, TCPM waits for PSSourceOffTimer for PS_READY message from the partner: FR_SWAP_SNK_SRC_NEW_SINK_READY. TCPC is expected to autonomously turn on vbus once the FRS signal is received and vbus voltage falls below vsafe5v within tSrcFrSwap. This is different from traditional power role swap where the vbus sourcing is turned on by TCPM. 4. By this time, TCPC most likely would have started to source vbus, TCPM waits for tSrcFrSwap to see if the lower level TCPC driver signals TCPM_SOURCING_VBUS event: FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED. 5. When TCPC signals sourcing vbus, TCPM sends PS_READY msg and changes the CC pin from Rd to Rp. This is the end of fast role swap sequence and TCPM initiates the sequnce to negotiate explicit contract by transitioning into SRC_STARTUP after SwapSrcStart. The code is written based on the sequence described in "Figure 8-107: Dual-role Port in Sink to Source Fast Role Swap State Diagram" of USB Power Delivery Specification Revision 3.0, Version 1.2. Signed-off-by: Badhri Jagan Sridharan <badhri@google.com> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Link: https://lore.kernel.org/r/20201008061556.1402293-7-badhri@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2020-10-08 06:15:47 +00:00
#define PDO_FIXED_FRS_CURR_MASK (BIT(24) | BIT(23)) /* FR_Swap Current (Sink) */
#define PDO_FIXED_FRS_CURR_SHIFT 23
#define PDO_FIXED_VOLT_SHIFT 10 /* 50mV units */
#define PDO_FIXED_CURR_SHIFT 0 /* 10mA units */
#define PDO_FIXED_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_FIXED_VOLT_SHIFT)
#define PDO_FIXED_CURR(ma) ((((ma) / 10) & PDO_CURR_MASK) << PDO_FIXED_CURR_SHIFT)
#define PDO_FIXED(mv, ma, flags) \
(PDO_TYPE(PDO_TYPE_FIXED) | (flags) | \
PDO_FIXED_VOLT(mv) | PDO_FIXED_CURR(ma))
#define VSAFE5V 5000 /* mv units */
#define PDO_BATT_MAX_VOLT_SHIFT 20 /* 50mV units */
#define PDO_BATT_MIN_VOLT_SHIFT 10 /* 50mV units */
#define PDO_BATT_MAX_PWR_SHIFT 0 /* 250mW units */
#define PDO_BATT_MIN_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_BATT_MIN_VOLT_SHIFT)
#define PDO_BATT_MAX_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_BATT_MAX_VOLT_SHIFT)
#define PDO_BATT_MAX_POWER(mw) ((((mw) / 250) & PDO_PWR_MASK) << PDO_BATT_MAX_PWR_SHIFT)
#define PDO_BATT(min_mv, max_mv, max_mw) \
(PDO_TYPE(PDO_TYPE_BATT) | PDO_BATT_MIN_VOLT(min_mv) | \
PDO_BATT_MAX_VOLT(max_mv) | PDO_BATT_MAX_POWER(max_mw))
#define PDO_VAR_MAX_VOLT_SHIFT 20 /* 50mV units */
#define PDO_VAR_MIN_VOLT_SHIFT 10 /* 50mV units */
#define PDO_VAR_MAX_CURR_SHIFT 0 /* 10mA units */
#define PDO_VAR_MIN_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_VAR_MIN_VOLT_SHIFT)
#define PDO_VAR_MAX_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_VAR_MAX_VOLT_SHIFT)
#define PDO_VAR_MAX_CURR(ma) ((((ma) / 10) & PDO_CURR_MASK) << PDO_VAR_MAX_CURR_SHIFT)
#define PDO_VAR(min_mv, max_mv, max_ma) \
(PDO_TYPE(PDO_TYPE_VAR) | PDO_VAR_MIN_VOLT(min_mv) | \
PDO_VAR_MAX_VOLT(max_mv) | PDO_VAR_MAX_CURR(max_ma))
enum pd_apdo_type {
APDO_TYPE_PPS = 0,
};
#define PDO_APDO_TYPE_SHIFT 28 /* Only valid value currently is 0x0 - PPS */
#define PDO_APDO_TYPE_MASK 0x3
#define PDO_APDO_TYPE(t) ((t) << PDO_APDO_TYPE_SHIFT)
#define PDO_PPS_APDO_MAX_VOLT_SHIFT 17 /* 100mV units */
#define PDO_PPS_APDO_MIN_VOLT_SHIFT 8 /* 100mV units */
#define PDO_PPS_APDO_MAX_CURR_SHIFT 0 /* 50mA units */
#define PDO_PPS_APDO_VOLT_MASK 0xff
#define PDO_PPS_APDO_CURR_MASK 0x7f
#define PDO_PPS_APDO_MIN_VOLT(mv) \
((((mv) / 100) & PDO_PPS_APDO_VOLT_MASK) << PDO_PPS_APDO_MIN_VOLT_SHIFT)
#define PDO_PPS_APDO_MAX_VOLT(mv) \
((((mv) / 100) & PDO_PPS_APDO_VOLT_MASK) << PDO_PPS_APDO_MAX_VOLT_SHIFT)
#define PDO_PPS_APDO_MAX_CURR(ma) \
((((ma) / 50) & PDO_PPS_APDO_CURR_MASK) << PDO_PPS_APDO_MAX_CURR_SHIFT)
#define PDO_PPS_APDO(min_mv, max_mv, max_ma) \
(PDO_TYPE(PDO_TYPE_APDO) | PDO_APDO_TYPE(APDO_TYPE_PPS) | \
PDO_PPS_APDO_MIN_VOLT(min_mv) | PDO_PPS_APDO_MAX_VOLT(max_mv) | \
PDO_PPS_APDO_MAX_CURR(max_ma))
static inline enum pd_pdo_type pdo_type(u32 pdo)
{
return (pdo >> PDO_TYPE_SHIFT) & PDO_TYPE_MASK;
}
static inline unsigned int pdo_fixed_voltage(u32 pdo)
{
return ((pdo >> PDO_FIXED_VOLT_SHIFT) & PDO_VOLT_MASK) * 50;
}
static inline unsigned int pdo_min_voltage(u32 pdo)
{
return ((pdo >> PDO_VAR_MIN_VOLT_SHIFT) & PDO_VOLT_MASK) * 50;
}
static inline unsigned int pdo_max_voltage(u32 pdo)
{
return ((pdo >> PDO_VAR_MAX_VOLT_SHIFT) & PDO_VOLT_MASK) * 50;
}
static inline unsigned int pdo_max_current(u32 pdo)
{
return ((pdo >> PDO_VAR_MAX_CURR_SHIFT) & PDO_CURR_MASK) * 10;
}
static inline unsigned int pdo_max_power(u32 pdo)
{
return ((pdo >> PDO_BATT_MAX_PWR_SHIFT) & PDO_PWR_MASK) * 250;
}
static inline enum pd_apdo_type pdo_apdo_type(u32 pdo)
{
return (pdo >> PDO_APDO_TYPE_SHIFT) & PDO_APDO_TYPE_MASK;
}
static inline unsigned int pdo_pps_apdo_min_voltage(u32 pdo)
{
return ((pdo >> PDO_PPS_APDO_MIN_VOLT_SHIFT) &
PDO_PPS_APDO_VOLT_MASK) * 100;
}
static inline unsigned int pdo_pps_apdo_max_voltage(u32 pdo)
{
return ((pdo >> PDO_PPS_APDO_MAX_VOLT_SHIFT) &
PDO_PPS_APDO_VOLT_MASK) * 100;
}
static inline unsigned int pdo_pps_apdo_max_current(u32 pdo)
{
return ((pdo >> PDO_PPS_APDO_MAX_CURR_SHIFT) &
PDO_PPS_APDO_CURR_MASK) * 50;
}
/* RDO: Request Data Object */
#define RDO_OBJ_POS_SHIFT 28
#define RDO_OBJ_POS_MASK 0x7
#define RDO_GIVE_BACK BIT(27) /* Supports reduced operating current */
#define RDO_CAP_MISMATCH BIT(26) /* Not satisfied by source caps */
#define RDO_USB_COMM BIT(25) /* USB communications capable */
#define RDO_NO_SUSPEND BIT(24) /* USB Suspend not supported */
#define RDO_PWR_MASK 0x3ff
#define RDO_CURR_MASK 0x3ff
#define RDO_FIXED_OP_CURR_SHIFT 10
#define RDO_FIXED_MAX_CURR_SHIFT 0
#define RDO_OBJ(idx) (((idx) & RDO_OBJ_POS_MASK) << RDO_OBJ_POS_SHIFT)
#define PDO_FIXED_OP_CURR(ma) ((((ma) / 10) & RDO_CURR_MASK) << RDO_FIXED_OP_CURR_SHIFT)
#define PDO_FIXED_MAX_CURR(ma) ((((ma) / 10) & RDO_CURR_MASK) << RDO_FIXED_MAX_CURR_SHIFT)
#define RDO_FIXED(idx, op_ma, max_ma, flags) \
(RDO_OBJ(idx) | (flags) | \
PDO_FIXED_OP_CURR(op_ma) | PDO_FIXED_MAX_CURR(max_ma))
#define RDO_BATT_OP_PWR_SHIFT 10 /* 250mW units */
#define RDO_BATT_MAX_PWR_SHIFT 0 /* 250mW units */
#define RDO_BATT_OP_PWR(mw) ((((mw) / 250) & RDO_PWR_MASK) << RDO_BATT_OP_PWR_SHIFT)
#define RDO_BATT_MAX_PWR(mw) ((((mw) / 250) & RDO_PWR_MASK) << RDO_BATT_MAX_PWR_SHIFT)
#define RDO_BATT(idx, op_mw, max_mw, flags) \
(RDO_OBJ(idx) | (flags) | \
RDO_BATT_OP_PWR(op_mw) | RDO_BATT_MAX_PWR(max_mw))
#define RDO_PROG_VOLT_MASK 0x7ff
#define RDO_PROG_CURR_MASK 0x7f
#define RDO_PROG_VOLT_SHIFT 9
#define RDO_PROG_CURR_SHIFT 0
#define RDO_PROG_VOLT_MV_STEP 20
#define RDO_PROG_CURR_MA_STEP 50
#define PDO_PROG_OUT_VOLT(mv) \
((((mv) / RDO_PROG_VOLT_MV_STEP) & RDO_PROG_VOLT_MASK) << RDO_PROG_VOLT_SHIFT)
#define PDO_PROG_OP_CURR(ma) \
((((ma) / RDO_PROG_CURR_MA_STEP) & RDO_PROG_CURR_MASK) << RDO_PROG_CURR_SHIFT)
#define RDO_PROG(idx, out_mv, op_ma, flags) \
(RDO_OBJ(idx) | (flags) | \
PDO_PROG_OUT_VOLT(out_mv) | PDO_PROG_OP_CURR(op_ma))
static inline unsigned int rdo_index(u32 rdo)
{
return (rdo >> RDO_OBJ_POS_SHIFT) & RDO_OBJ_POS_MASK;
}
static inline unsigned int rdo_op_current(u32 rdo)
{
return ((rdo >> RDO_FIXED_OP_CURR_SHIFT) & RDO_CURR_MASK) * 10;
}
static inline unsigned int rdo_max_current(u32 rdo)
{
return ((rdo >> RDO_FIXED_MAX_CURR_SHIFT) &
RDO_CURR_MASK) * 10;
}
static inline unsigned int rdo_op_power(u32 rdo)
{
return ((rdo >> RDO_BATT_OP_PWR_SHIFT) & RDO_PWR_MASK) * 250;
}
static inline unsigned int rdo_max_power(u32 rdo)
{
return ((rdo >> RDO_BATT_MAX_PWR_SHIFT) & RDO_PWR_MASK) * 250;
}
/* Enter_USB Data Object */
#define EUDO_USB_MODE_MASK GENMASK(30, 28)
#define EUDO_USB_MODE_SHIFT 28
#define EUDO_USB_MODE_USB2 0
#define EUDO_USB_MODE_USB3 1
#define EUDO_USB_MODE_USB4 2
#define EUDO_USB4_DRD BIT(26)
#define EUDO_USB3_DRD BIT(25)
#define EUDO_CABLE_SPEED_MASK GENMASK(23, 21)
#define EUDO_CABLE_SPEED_SHIFT 21
#define EUDO_CABLE_SPEED_USB2 0
#define EUDO_CABLE_SPEED_USB3_GEN1 1
#define EUDO_CABLE_SPEED_USB4_GEN2 2
#define EUDO_CABLE_SPEED_USB4_GEN3 3
#define EUDO_CABLE_TYPE_MASK GENMASK(20, 19)
#define EUDO_CABLE_TYPE_SHIFT 19
#define EUDO_CABLE_TYPE_PASSIVE 0
#define EUDO_CABLE_TYPE_RE_TIMER 1
#define EUDO_CABLE_TYPE_RE_DRIVER 2
#define EUDO_CABLE_TYPE_OPTICAL 3
#define EUDO_CABLE_CURRENT_MASK GENMASK(18, 17)
#define EUDO_CABLE_CURRENT_SHIFT 17
#define EUDO_CABLE_CURRENT_NOTSUPP 0
#define EUDO_CABLE_CURRENT_3A 2
#define EUDO_CABLE_CURRENT_5A 3
#define EUDO_PCIE_SUPPORT BIT(16)
#define EUDO_DP_SUPPORT BIT(15)
#define EUDO_TBT_SUPPORT BIT(14)
#define EUDO_HOST_PRESENT BIT(13)
/* USB PD timers and counters */
#define PD_T_NO_RESPONSE 5000 /* 4.5 - 5.5 seconds */
#define PD_T_DB_DETECT 10000 /* 10 - 15 seconds */
#define PD_T_SEND_SOURCE_CAP 150 /* 100 - 200 ms */
#define PD_T_SENDER_RESPONSE 60 /* 24 - 30 ms, relaxed */
usb: typec: tcpm: Add support for Sink Fast Role SWAP(FRS) PD 3.0 spec defines a new mechanism for power role swap called Fast role swap. This change enables TCPM to support FRS when acting as sink. Once the explicit contract is negotiated, sink port is expected to query the source port for sink caps to determine whether the source is FRS capable. Bits 23 & 24 of fixed pdo of the sink caps from the source, when set, indicates the current needed by the source when fast role swap is in progress(Implicit contract phasae). 0 indicates that the source does not support Fast Role Swap. Upon receiving the FRS signal from the source, TCPC(TCPM_FRS_EVENT) informs TCPM to start the Fast role swap sequence. 1. TCPM sends FRS PD message: FR_SWAP_SEND 2. If response is not received within the expiry of SenderResponseTimer, Error recovery is triggered.: FR_SWAP_SEND_TIMEOUT 3. Upon receipt of the accept message, TCPM waits for PSSourceOffTimer for PS_READY message from the partner: FR_SWAP_SNK_SRC_NEW_SINK_READY. TCPC is expected to autonomously turn on vbus once the FRS signal is received and vbus voltage falls below vsafe5v within tSrcFrSwap. This is different from traditional power role swap where the vbus sourcing is turned on by TCPM. 4. By this time, TCPC most likely would have started to source vbus, TCPM waits for tSrcFrSwap to see if the lower level TCPC driver signals TCPM_SOURCING_VBUS event: FR_SWAP_SNK_SRC_SOURCE_VBUS_APPLIED. 5. When TCPC signals sourcing vbus, TCPM sends PS_READY msg and changes the CC pin from Rd to Rp. This is the end of fast role swap sequence and TCPM initiates the sequnce to negotiate explicit contract by transitioning into SRC_STARTUP after SwapSrcStart. The code is written based on the sequence described in "Figure 8-107: Dual-role Port in Sink to Source Fast Role Swap State Diagram" of USB Power Delivery Specification Revision 3.0, Version 1.2. Signed-off-by: Badhri Jagan Sridharan <badhri@google.com> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Link: https://lore.kernel.org/r/20201008061556.1402293-7-badhri@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2020-10-08 06:15:47 +00:00
#define PD_T_RECEIVER_RESPONSE 15 /* 15ms max */
#define PD_T_SOURCE_ACTIVITY 45
#define PD_T_SINK_ACTIVITY 135
#define PD_T_SINK_WAIT_CAP 310 /* 310 - 620 ms */
#define PD_T_PS_TRANSITION 500
#define PD_T_SRC_TRANSITION 35
#define PD_T_DRP_SNK 40
#define PD_T_DRP_SRC 30
#define PD_T_PS_SOURCE_OFF 920
#define PD_T_PS_SOURCE_ON 480
#define PD_T_PS_SOURCE_ON_PRS 450 /* 390 - 480ms */
#define PD_T_PS_HARD_RESET 30
#define PD_T_SRC_RECOVER 760
#define PD_T_SRC_RECOVER_MAX 1000
#define PD_T_SRC_TURN_ON 275
#define PD_T_SAFE_0V 650
#define PD_T_VCONN_SOURCE_ON 100
#define PD_T_SINK_REQUEST 100 /* 100 ms minimum */
#define PD_T_ERROR_RECOVERY 100 /* minimum 25 is insufficient */
#define PD_T_SRCSWAPSTDBY 625 /* Maximum of 650ms */
#define PD_T_NEWSRC 250 /* Maximum of 275ms */
usb: typec: tcpm: During PR_SWAP, source caps should be sent only after tSwapSourceStart The patch addresses the compliance test failures while running TD.PD.CP.E3, TD.PD.CP.E4, TD.PD.CP.E5 of the "Deterministic PD Compliance MOI" test plan published in https://www.usb.org/usbc. For a product to be Type-C compliant, it's expected that these tests are run on usb.org certified Type-C compliance tester as mentioned in https://www.usb.org/usbc. The purpose of the tests TD.PD.CP.E3, TD.PD.CP.E4, TD.PD.CP.E5 is to verify the PR_SWAP response of the device. While doing so, the test asserts that Source Capabilities message is NOT received from the test device within tSwapSourceStart min (20 ms) from the time the last bit of GoodCRC corresponding to the RS_RDY message sent by the UUT was sent. If it does then the test fails. This is in line with the requirements from the USB Power Delivery Specification Revision 3.0, Version 1.2: "6.6.8.1 SwapSourceStartTimer The SwapSourceStartTimer Shall be used by the new Source, after a Power Role Swap or Fast Role Swap, to ensure that it does not send Source_Capabilities Message before the new Sink is ready to receive the Source_Capabilities Message. The new Source Shall Not send the Source_Capabilities Message earlier than tSwapSourceStart after the last bit of the EOP of GoodCRC Message sent in response to the PS_RDY Message sent by the new Source indicating that its power supply is ready." The patch makes sure that TCPM does not send the Source_Capabilities Message within tSwapSourceStart(20ms) by transitioning into SRC_STARTUP only after tSwapSourceStart(20ms). Signed-off-by: Badhri Jagan Sridharan <badhri@google.com> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Link: https://lore.kernel.org/r/20200817183828.1895015-1-badhri@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2020-08-17 18:38:27 +00:00
#define PD_T_SWAP_SRC_START 20 /* Minimum of 20ms */
#define PD_T_BIST_CONT_MODE 50 /* 30 - 60 ms */
#define PD_T_SINK_TX 16 /* 16 - 20 ms */
#define PD_T_CHUNK_NOT_SUPP 42 /* 40 - 50 ms */
#define PD_T_DRP_TRY 100 /* 75 - 150 ms */
#define PD_T_DRP_TRYWAIT 600 /* 400 - 800 ms */
#define PD_T_CC_DEBOUNCE 200 /* 100 - 200 ms */
#define PD_T_PD_DEBOUNCE 20 /* 10 - 20 ms */
#define PD_T_TRY_CC_DEBOUNCE 15 /* 10 - 20 ms */
#define PD_N_CAPS_COUNT (PD_T_NO_RESPONSE / PD_T_SEND_SOURCE_CAP)
#define PD_N_HARD_RESET_COUNT 2
usb: typec: tcpm: Honour pSnkStdby requirement during negotiation >From PD Spec: The Sink Shall transition to Sink Standby before a positive or negative voltage transition of VBUS. During Sink Standby the Sink Shall reduce its power draw to pSnkStdby. This allows the Source to manage the voltage transition as well as supply sufficient operating current to the Sink to maintain PD operation during the transition. The Sink Shall complete this transition to Sink Standby within tSnkStdby after evaluating the Accept Message from the Source. The transition when returning to Sink operation from Sink Standby Shall be completed within tSnkNewPower. The pSnkStdby requirement Shall only apply if the Sink power draw is higher than this level. The above requirement needs to be met to prevent hard resets from port partner. Without the patch: (5V/3A during SNK_DISCOVERY all the way through explicit contract) [ 95.711984] CC1: 0 -> 0, CC2: 0 -> 5 [state TOGGLING, polarity 0, connected] [ 95.712007] state change TOGGLING -> SNK_ATTACH_WAIT [rev3 NONE_AMS] [ 95.712017] pending state change SNK_ATTACH_WAIT -> SNK_DEBOUNCED @ 170 ms [rev3 NONE_AMS] [ 95.837190] VBUS on [ 95.882075] state change SNK_ATTACH_WAIT -> SNK_DEBOUNCED [delayed 170 ms] [ 95.882082] state change SNK_DEBOUNCED -> SNK_ATTACHED [rev3 NONE_AMS] [ 95.882086] polarity 1 [ 95.883151] set_auto_vbus_discharge_threshold mode:0 pps_active:n vbus:5000 ret:0 [ 95.883441] enable vbus discharge ret:0 [ 95.883445] Requesting mux state 1, usb-role 2, orientation 2 [ 95.883776] state change SNK_ATTACHED -> SNK_STARTUP [rev3 NONE_AMS] [ 95.883879] pending state change SNK_STARTUP -> SNK_DISCOVERY @ 500 ms [rev3 NONE_AMS] [ 96.038960] VBUS on [ 96.383939] state change SNK_STARTUP -> SNK_DISCOVERY [delayed 500 ms] [ 96.383946] Setting voltage/current limit 5000 mV 3000 mA [ 96.383961] vbus=0 charge:=1 [ 96.386044] state change SNK_DISCOVERY -> SNK_WAIT_CAPABILITIES [rev3 NONE_AMS] [ 96.386309] pending state change SNK_WAIT_CAPABILITIES -> HARD_RESET_SEND @ 450 ms [rev3 NONE_AMS] [ 96.394404] PD RX, header: 0x2161 [1] [ 96.394408] PDO 0: type 0, 5000 mV, 3000 mA [E] [ 96.394410] PDO 1: type 0, 9000 mV, 2000 mA [] [ 96.394412] state change SNK_WAIT_CAPABILITIES -> SNK_NEGOTIATE_CAPABILITIES [rev2 POWER_NEGOTIATION] [ 96.394416] Setting usb_comm capable false [ 96.395083] cc=0 cc1=0 cc2=5 vbus=0 vconn=sink polarity=1 [ 96.395089] Requesting PDO 1: 9000 mV, 2000 mA [ 96.395093] PD TX, header: 0x1042 [ 96.397404] PD TX complete, status: 0 [ 96.397424] pending state change SNK_NEGOTIATE_CAPABILITIES -> HARD_RESET_SEND @ 60 ms [rev2 POWER_NEGOTIATION] [ 96.400826] PD RX, header: 0x363 [1] [ 96.400829] state change SNK_NEGOTIATE_CAPABILITIES -> SNK_TRANSITION_SINK [rev2 POWER_NEGOTIATION] [ 96.400832] pending state change SNK_TRANSITION_SINK -> HARD_RESET_SEND @ 500 ms [rev2 POWER_NEGOTIATION] [ 96.577315] PD RX, header: 0x566 [1] [ 96.577321] Setting voltage/current limit 9000 mV 2000 mA [ 96.578363] set_auto_vbus_discharge_threshold mode:3 pps_active:n vbus:9000 ret:0 [ 96.578370] state change SNK_TRANSITION_SINK -> SNK_READY [rev2 POWER_NEGOTIATION] With the patch: [ 168.398573] CC1: 0 -> 0, CC2: 0 -> 5 [state TOGGLING, polarity 0, connected] [ 168.398605] state change TOGGLING -> SNK_ATTACH_WAIT [rev3 NONE_AMS] [ 168.398619] pending state change SNK_ATTACH_WAIT -> SNK_DEBOUNCED @ 170 ms [rev3 NONE_AMS] [ 168.522348] VBUS on [ 168.568676] state change SNK_ATTACH_WAIT -> SNK_DEBOUNCED [delayed 170 ms] [ 168.568684] state change SNK_DEBOUNCED -> SNK_ATTACHED [rev3 NONE_AMS] [ 168.568688] polarity 1 [ 168.569867] set_auto_vbus_discharge_threshold mode:0 pps_active:n vbus:5000 ret:0 [ 168.570158] enable vbus discharge ret:0 [ 168.570161] Requesting mux state 1, usb-role 2, orientation 2 [ 168.570504] state change SNK_ATTACHED -> SNK_STARTUP [rev3 NONE_AMS] [ 168.570634] pending state change SNK_STARTUP -> SNK_DISCOVERY @ 500 ms [rev3 NONE_AMS] [ 169.070689] state change SNK_STARTUP -> SNK_DISCOVERY [delayed 500 ms] [ 169.070695] Setting voltage/current limit 5000 mV 3000 mA [ 169.070702] vbus=0 charge:=1 [ 169.072719] state change SNK_DISCOVERY -> SNK_WAIT_CAPABILITIES [rev3 NONE_AMS] [ 169.073145] pending state change SNK_WAIT_CAPABILITIES -> HARD_RESET_SEND @ 450 ms [rev3 NONE_AMS] [ 169.077162] PD RX, header: 0x2161 [1] [ 169.077172] PDO 0: type 0, 5000 mV, 3000 mA [E] [ 169.077178] PDO 1: type 0, 9000 mV, 2000 mA [] [ 169.077183] state change SNK_WAIT_CAPABILITIES -> SNK_NEGOTIATE_CAPABILITIES [rev2 POWER_NEGOTIATION] [ 169.077191] Setting usb_comm capable false [ 169.077753] cc=0 cc1=0 cc2=5 vbus=0 vconn=sink polarity=1 [ 169.077759] Requesting PDO 1: 9000 mV, 2000 mA [ 169.077762] PD TX, header: 0x1042 [ 169.079990] PD TX complete, status: 0 [ 169.080013] pending state change SNK_NEGOTIATE_CAPABILITIES -> HARD_RESET_SEND @ 60 ms [rev2 POWER_NEGOTIATION] [ 169.083183] VBUS on [ 169.084195] PD RX, header: 0x363 [1] [ 169.084200] state change SNK_NEGOTIATE_CAPABILITIES -> SNK_TRANSITION_SINK [rev2 POWER_NEGOTIATION] [ 169.084206] Setting standby current 5000 mV @ 500 mA [ 169.084209] Setting voltage/current limit 5000 mV 500 mA [ 169.084220] pending state change SNK_TRANSITION_SINK -> HARD_RESET_SEND @ 500 ms [rev2 POWER_NEGOTIATION] [ 169.260222] PD RX, header: 0x566 [1] [ 169.260227] Setting voltage/current limit 9000 mV 2000 mA [ 169.261315] set_auto_vbus_discharge_threshold mode:3 pps_active:n vbus:9000 ret:0 [ 169.261321] state change SNK_TRANSITION_SINK -> SNK_READY [rev2 POWER_NEGOTIATION] [ 169.261570] AMS POWER_NEGOTIATION finished Fixes: f0690a25a140b ("staging: typec: USB Type-C Port Manager (tcpm)") Reviewed-by: Guenter Roeck <linux@roeck-us.net> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Signed-off-by: Badhri Jagan Sridharan <badhri@google.com> Link: https://lore.kernel.org/r/20210414024000.4175263-1-badhri@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-04-14 02:39:58 +00:00
#define PD_P_SNK_STDBY_MW 2500 /* 2500 mW */
#if IS_ENABLED(CONFIG_TYPEC)
struct usb_power_delivery;
/**
* usb_power_delivery_desc - USB Power Delivery Descriptor
* @revision: USB Power Delivery Specification Revision
* @version: USB Power Delivery Specicication Version - optional
*/
struct usb_power_delivery_desc {
u16 revision;
u16 version;
};
/**
* usb_power_delivery_capabilities_desc - Description of USB Power Delivery Capabilities Message
* @pdo: The Power Data Objects in the Capability Message
* @role: Power role of the capabilities
*/
struct usb_power_delivery_capabilities_desc {
u32 pdo[PDO_MAX_OBJECTS];
enum typec_role role;
};
struct usb_power_delivery_capabilities *
usb_power_delivery_register_capabilities(struct usb_power_delivery *pd,
struct usb_power_delivery_capabilities_desc *desc);
void usb_power_delivery_unregister_capabilities(struct usb_power_delivery_capabilities *cap);
struct usb_power_delivery *usb_power_delivery_register(struct device *parent,
struct usb_power_delivery_desc *desc);
void usb_power_delivery_unregister(struct usb_power_delivery *pd);
int usb_power_delivery_link_device(struct usb_power_delivery *pd, struct device *dev);
void usb_power_delivery_unlink_device(struct usb_power_delivery *pd, struct device *dev);
#endif /* CONFIG_TYPEC */
#endif /* __LINUX_USB_PD_H */