Commit 8dc4bd07 authored by Badhri Jagan Sridharan's avatar Badhri Jagan Sridharan Committed by Greg Kroah-Hartman

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: default avatarBadhri Jagan Sridharan <badhri@google.com>
Reviewed-by: default avatarHeikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://lore.kernel.org/r/20201008061556.1402293-7-badhri@google.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 6f413b55
This diff is collapsed.
...@@ -219,14 +219,16 @@ enum pd_pdo_type { ...@@ -219,14 +219,16 @@ enum pd_pdo_type {
#define PDO_CURR_MASK 0x3ff #define PDO_CURR_MASK 0x3ff
#define PDO_PWR_MASK 0x3ff #define PDO_PWR_MASK 0x3ff
#define PDO_FIXED_DUAL_ROLE BIT(29) /* Power role swap supported */ #define PDO_FIXED_DUAL_ROLE BIT(29) /* Power role swap supported */
#define PDO_FIXED_SUSPEND BIT(28) /* USB Suspend supported (Source) */ #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_HIGHER_CAP BIT(28) /* Requires more than vSafe5V (Sink) */
#define PDO_FIXED_EXTPOWER BIT(27) /* Externally powered */ #define PDO_FIXED_EXTPOWER BIT(27) /* Externally powered */
#define PDO_FIXED_USB_COMM BIT(26) /* USB communications capable */ #define PDO_FIXED_USB_COMM BIT(26) /* USB communications capable */
#define PDO_FIXED_DATA_SWAP BIT(25) /* Data role swap supported */ #define PDO_FIXED_DATA_SWAP BIT(25) /* Data role swap supported */
#define PDO_FIXED_VOLT_SHIFT 10 /* 50mV units */ #define PDO_FIXED_FRS_CURR_MASK (BIT(24) | BIT(23)) /* FR_Swap Current (Sink) */
#define PDO_FIXED_CURR_SHIFT 0 /* 10mA units */ #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_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_CURR(ma) ((((ma) / 10) & PDO_CURR_MASK) << PDO_FIXED_CURR_SHIFT)
...@@ -454,6 +456,7 @@ static inline unsigned int rdo_max_power(u32 rdo) ...@@ -454,6 +456,7 @@ static inline unsigned int rdo_max_power(u32 rdo)
#define PD_T_DB_DETECT 10000 /* 10 - 15 seconds */ #define PD_T_DB_DETECT 10000 /* 10 - 15 seconds */
#define PD_T_SEND_SOURCE_CAP 150 /* 100 - 200 ms */ #define PD_T_SEND_SOURCE_CAP 150 /* 100 - 200 ms */
#define PD_T_SENDER_RESPONSE 60 /* 24 - 30 ms, relaxed */ #define PD_T_SENDER_RESPONSE 60 /* 24 - 30 ms, relaxed */
#define PD_T_RECEIVER_RESPONSE 15 /* 15ms max */
#define PD_T_SOURCE_ACTIVITY 45 #define PD_T_SOURCE_ACTIVITY 45
#define PD_T_SINK_ACTIVITY 135 #define PD_T_SINK_ACTIVITY 135
#define PD_T_SINK_WAIT_CAP 240 #define PD_T_SINK_WAIT_CAP 240
......
...@@ -78,8 +78,11 @@ enum tcpm_transmit_type { ...@@ -78,8 +78,11 @@ enum tcpm_transmit_type {
* automatically if a connection is established. * automatically if a connection is established.
* @try_role: Optional; called to set a preferred role * @try_role: Optional; called to set a preferred role
* @pd_transmit:Called to transmit PD message * @pd_transmit:Called to transmit PD message
* @mux: Pointer to multiplexer data
* @set_bist_data: Turn on/off bist data mode for compliance testing * @set_bist_data: Turn on/off bist data mode for compliance testing
* @enable_frs:
* Optional; Called to enable/disable PD 3.0 fast role swap.
* Enabling frs is accessory dependent as not all PD3.0
* accessories support fast role swap.
*/ */
struct tcpc_dev { struct tcpc_dev {
struct fwnode_handle *fwnode; struct fwnode_handle *fwnode;
...@@ -105,6 +108,7 @@ struct tcpc_dev { ...@@ -105,6 +108,7 @@ struct tcpc_dev {
int (*pd_transmit)(struct tcpc_dev *dev, enum tcpm_transmit_type type, int (*pd_transmit)(struct tcpc_dev *dev, enum tcpm_transmit_type type,
const struct pd_message *msg); const struct pd_message *msg);
int (*set_bist_data)(struct tcpc_dev *dev, bool on); int (*set_bist_data)(struct tcpc_dev *dev, bool on);
int (*enable_frs)(struct tcpc_dev *dev, bool enable);
}; };
struct tcpm_port; struct tcpm_port;
...@@ -114,6 +118,8 @@ void tcpm_unregister_port(struct tcpm_port *port); ...@@ -114,6 +118,8 @@ void tcpm_unregister_port(struct tcpm_port *port);
void tcpm_vbus_change(struct tcpm_port *port); void tcpm_vbus_change(struct tcpm_port *port);
void tcpm_cc_change(struct tcpm_port *port); void tcpm_cc_change(struct tcpm_port *port);
void tcpm_sink_frs(struct tcpm_port *port);
void tcpm_sourcing_vbus(struct tcpm_port *port);
void tcpm_pd_receive(struct tcpm_port *port, void tcpm_pd_receive(struct tcpm_port *port,
const struct pd_message *msg); const struct pd_message *msg);
void tcpm_pd_transmit_complete(struct tcpm_port *port, void tcpm_pd_transmit_complete(struct tcpm_port *port,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment