Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8549c91a authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: pd: Support revision 3.0 in sink-only mode"

parents 21905f93 be74622c
Loading
Loading
Loading
Loading
+43 −22
Original line number Diff line number Diff line
@@ -38,6 +38,10 @@ static bool disable_usb_pd;
module_param(disable_usb_pd, bool, 0644);
MODULE_PARM_DESC(disable_usb_pd, "Disable USB PD for USB3.1 compliance testing");

static bool rev3_sink_only;
module_param(rev3_sink_only, bool, 0644);
MODULE_PARM_DESC(rev3_sink_only, "Enable power delivery rev3.0 sink only mode");

enum usbpd_state {
	PE_UNKNOWN,
	PE_ERROR_RECOVERY,
@@ -533,21 +537,18 @@ static inline void pd_reset_protocol(struct usbpd *pd)
	pd->send_dr_swap = false;
}

static int pd_send_msg(struct usbpd *pd, u8 hdr_type, const u32 *data,
		size_t num_data, enum pd_msg_type type)
static int pd_send_msg(struct usbpd *pd, u8 msg_type, const u32 *data,
		size_t num_data, enum pd_sop_type sop)
{
	int ret;
	u16 hdr;

	hdr = PD_MSG_HDR(hdr_type, pd->current_dr, pd->current_pr,
	hdr = PD_MSG_HDR(msg_type, pd->current_dr, pd->current_pr,
			pd->tx_msgid, num_data, pd->spec_rev);
	ret = pd_phy_write(hdr, (u8 *)data, num_data * sizeof(u32), type, 15);
	/* TODO figure out timeout. based on tReceive=1.1ms x nRetryCount? */

	if (ret < 0)
	ret = pd_phy_write(hdr, (u8 *)data, num_data * sizeof(u32), sop);
	if (ret)
		return ret;
	else if (ret != num_data * sizeof(u32))
		return -EIO;

	pd->tx_msgid = (pd->tx_msgid + 1) & PD_MAX_MSG_ID;
	return 0;
@@ -609,7 +610,7 @@ static int pd_select_pdo(struct usbpd *pd, int pdo_pos, int uv, int ua)

static int pd_eval_src_caps(struct usbpd *pd)
{
	int obj_cnt;
	int i;
	union power_supply_propval val;
	u32 first_pdo = pd->received_pdos[0];

@@ -626,11 +627,20 @@ static int pd_eval_src_caps(struct usbpd *pd)
	power_supply_set_property(pd->usb_psy,
			POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED, &val);

	for (obj_cnt = 1; obj_cnt < PD_MAX_DATA_OBJ; obj_cnt++) {
		if ((PD_SRC_PDO_TYPE(pd->received_pdos[obj_cnt]) ==
	if (pd->spec_rev == USBPD_REV_30 && !rev3_sink_only) {
		bool pps_found = false;

		/* downgrade to 2.0 if no PPS */
		for (i = 1; i < PD_MAX_DATA_OBJ; i++) {
			if ((PD_SRC_PDO_TYPE(pd->received_pdos[i]) ==
					PD_SRC_PDO_TYPE_AUGMENTED) &&
				!PD_APDO_PPS(pd->received_pdos[obj_cnt]))
			pd->spec_rev = USBPD_REV_30;
				!PD_APDO_PPS(pd->received_pdos[i])) {
				pps_found = true;
				break;
			}
		}
		if (!pps_found)
			pd->spec_rev = USBPD_REV_20;
	}

	/* Select the first PDO (vSafe5V) immediately. */
@@ -648,7 +658,7 @@ static void pd_send_hard_reset(struct usbpd *pd)
	/* Force CC logic to source/sink to keep Rp/Rd unchanged */
	set_power_role(pd, pd->current_pr);
	pd->hard_reset_count++;
	pd_phy_signal(HARD_RESET_SIG, 5); /* tHardResetComplete */
	pd_phy_signal(HARD_RESET_SIG);
	pd->in_pr_swap = false;
	power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PR_SWAP, &val);
}
@@ -664,12 +674,12 @@ static void kick_sm(struct usbpd *pd, int ms)
		queue_work(pd->wq, &pd->sm_work);
}

static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type)
static void phy_sig_received(struct usbpd *pd, enum pd_sig_type sig)
{
	union power_supply_propval val = {1};

	if (type != HARD_RESET_SIG) {
		usbpd_err(&pd->dev, "invalid signal (%d) received\n", type);
	if (sig != HARD_RESET_SIG) {
		usbpd_err(&pd->dev, "invalid signal (%d) received\n", sig);
		return;
	}

@@ -684,16 +694,16 @@ static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type)
	kick_sm(pd, 0);
}

static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type,
static void phy_msg_received(struct usbpd *pd, enum pd_sop_type sop,
		u8 *buf, size_t len)
{
	struct rx_msg *rx_msg;
	unsigned long flags;
	u16 header;

	if (type != SOP_MSG) {
	if (sop != SOP_MSG) {
		usbpd_err(&pd->dev, "invalid msg type (%d) received; only SOP supported\n",
				type);
				sop);
		return;
	}

@@ -731,6 +741,10 @@ static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type,
		return;
	}

	/* if spec rev differs (i.e. is older), update PHY */
	if (PD_MSG_HDR_REV(header) < pd->spec_rev)
		pd->spec_rev = PD_MSG_HDR_REV(header);

	rx_msg = kzalloc(sizeof(*rx_msg), GFP_KERNEL);
	if (!rx_msg)
		return;
@@ -817,6 +831,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
		power_supply_set_property(pd->usb_psy,
				POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &val);

		/* support only PD 2.0 as a source */
		pd->spec_rev = USBPD_REV_20;
		pd_reset_protocol(pd);

		if (!pd->in_pr_swap) {
@@ -988,6 +1004,11 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
		if (!val.intval || disable_usb_pd)
			break;

		/*
		 * support up to PD 3.0 as a sink; if source is 2.0
		 * phy_msg_received() will handle the downgrade.
		 */
		pd->spec_rev = USBPD_REV_30;
		pd_reset_protocol(pd);

		if (!pd->in_pr_swap) {
@@ -1675,6 +1696,8 @@ static void usbpd_sm(struct work_struct *w)
		/* set due to dual_role class "mode" change */
		if (pd->forced_pr != POWER_SUPPLY_TYPEC_PR_NONE)
			val.intval = pd->forced_pr;
		else if (rev3_sink_only)
			val.intval = POWER_SUPPLY_TYPEC_PR_SINK;
		else
			/* Set CC back to DRP toggle */
			val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
@@ -3401,8 +3424,6 @@ struct usbpd *usbpd_create(struct device *parent)
		pd->dual_role->drv_data = pd;
	}

	/* default support as PD 2.0 source or sink */
	pd->spec_rev = USBPD_REV_20;
	pd->current_pr = PR_NONE;
	pd->current_dr = DR_NONE;
	list_add_tail(&pd->instance, &_usbpd);
+19 −15
Original line number Diff line number Diff line
@@ -80,6 +80,10 @@
#define VDD_PDPHY_VOL_MAX		3088000 /* uV */
#define VDD_PDPHY_HPM_LOAD		3000 /* uA */

/* timers */
#define RECEIVER_RESPONSE_TIME		15	/* tReceiverResponse */
#define HARD_RESET_COMPLETE_TIME	5	/* tHardResetComplete */

struct usb_pdphy {
	struct device *dev;
	struct regmap *regmap;
@@ -96,8 +100,8 @@ struct usb_pdphy {
	int msg_tx_discarded_irq;
	int msg_rx_discarded_irq;

	void (*signal_cb)(struct usbpd *pd, enum pd_sig_type type);
	void (*msg_rx_cb)(struct usbpd *pd, enum pd_msg_type type,
	void (*signal_cb)(struct usbpd *pd, enum pd_sig_type sig);
	void (*msg_rx_cb)(struct usbpd *pd, enum pd_sop_type sop,
			  u8 *buf, size_t len);
	void (*shutdown_cb)(struct usbpd *pd);

@@ -401,14 +405,13 @@ int pd_phy_open(struct pd_phy_params *params)
}
EXPORT_SYMBOL(pd_phy_open);

int pd_phy_signal(enum pd_sig_type type, unsigned int timeout_ms)
int pd_phy_signal(enum pd_sig_type sig)
{
	u8 val;
	int ret;
	struct usb_pdphy *pdphy = __pdphy;

	dev_dbg(pdphy->dev, "%s: type %d timeout %u\n", __func__, type,
			timeout_ms);
	dev_dbg(pdphy->dev, "%s: type %d\n", __func__, sig);

	if (!pdphy) {
		pr_err("%s: pdphy not found\n", __func__);
@@ -428,7 +431,7 @@ int pd_phy_signal(enum pd_sig_type type, unsigned int timeout_ms)

	usleep_range(2, 3);

	val = (type == CABLE_RESET_SIG ? TX_CONTROL_FRAME_TYPE_CABLE_RESET : 0)
	val = (sig == CABLE_RESET_SIG ? TX_CONTROL_FRAME_TYPE_CABLE_RESET : 0)
		| TX_CONTROL_SEND_SIGNAL;

	ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, val);
@@ -436,7 +439,8 @@ int pd_phy_signal(enum pd_sig_type type, unsigned int timeout_ms)
		return ret;

	ret = wait_event_interruptible_timeout(pdphy->tx_waitq,
		pdphy->tx_status != -EINPROGRESS, msecs_to_jiffies(timeout_ms));
		pdphy->tx_status != -EINPROGRESS,
		msecs_to_jiffies(HARD_RESET_COMPLETE_TIME));
	if (ret <= 0) {
		dev_err(pdphy->dev, "%s: failed ret %d", __func__, ret);
		return ret ? ret : -ETIMEDOUT;
@@ -447,7 +451,7 @@ int pd_phy_signal(enum pd_sig_type type, unsigned int timeout_ms)
	if (pdphy->tx_status)
		return pdphy->tx_status;

	if (type == HARD_RESET_SIG)
	if (sig == HARD_RESET_SIG)
		/* Frame filter is reconfigured in pd_phy_open() */
		return pdphy_reg_write(pdphy, USB_PDPHY_FRAME_FILTER, 0);

@@ -455,16 +459,15 @@ int pd_phy_signal(enum pd_sig_type type, unsigned int timeout_ms)
}
EXPORT_SYMBOL(pd_phy_signal);

int pd_phy_write(u16 hdr, const u8 *data, size_t data_len,
	enum pd_msg_type type, unsigned int timeout_ms)
int pd_phy_write(u16 hdr, const u8 *data, size_t data_len, enum pd_sop_type sop)
{
	u8 val;
	int ret;
	size_t total_len = data_len + USB_PDPHY_MSG_HDR_LEN;
	struct usb_pdphy *pdphy = __pdphy;

	dev_dbg(pdphy->dev, "%s: hdr %x frame type %d timeout %u\n",
			__func__, hdr, type, timeout_ms);
	dev_dbg(pdphy->dev, "%s: hdr %x frame sop_type %d\n",
			__func__, hdr, sop);

	if (data && data_len)
		print_hex_dump_debug("tx data obj:", DUMP_PREFIX_NONE, 32, 4,
@@ -518,14 +521,15 @@ int pd_phy_write(u16 hdr, const u8 *data, size_t data_len,

	usleep_range(2, 3);

	val = TX_CONTROL_RETRY_COUNT | (type << 2) | TX_CONTROL_SEND_MSG;
	val = TX_CONTROL_RETRY_COUNT | (sop << 2) | TX_CONTROL_SEND_MSG;

	ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, val);
	if (ret)
		return ret;

	ret = wait_event_interruptible_timeout(pdphy->tx_waitq,
		pdphy->tx_status != -EINPROGRESS, msecs_to_jiffies(timeout_ms));
		pdphy->tx_status != -EINPROGRESS,
		msecs_to_jiffies(RECEIVER_RESPONSE_TIME));
	if (ret <= 0) {
		dev_err(pdphy->dev, "%s: failed ret %d", __func__, ret);
		return ret ? ret : -ETIMEDOUT;
@@ -534,7 +538,7 @@ int pd_phy_write(u16 hdr, const u8 *data, size_t data_len,
	if (hdr && !pdphy->tx_status)
		pdphy->tx_bytes += data_len + USB_PDPHY_MSG_HDR_LEN;

	return pdphy->tx_status ? pdphy->tx_status : data_len;
	return pdphy->tx_status ? pdphy->tx_status : 0;
}
EXPORT_SYMBOL(pd_phy_write);

+7 −7
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ enum pd_sig_type {
	CABLE_RESET_SIG,
};

enum pd_msg_type {
enum pd_sop_type {
	SOP_MSG = 0,
	SOPI_MSG,
	SOPII_MSG,
@@ -61,8 +61,8 @@ enum pd_spec_rev {
#define FRAME_FILTER_EN_HARD_RESET	BIT(5)

struct pd_phy_params {
	void		(*signal_cb)(struct usbpd *pd, enum pd_sig_type type);
	void		(*msg_rx_cb)(struct usbpd *pd, enum pd_msg_type type,
	void		(*signal_cb)(struct usbpd *pd, enum pd_sig_type sig);
	void		(*msg_rx_cb)(struct usbpd *pd, enum pd_sop_type sop,
					u8 *buf, size_t len);
	void		(*shutdown_cb)(struct usbpd *pd);
	enum data_role	data_role;
@@ -72,9 +72,9 @@ struct pd_phy_params {

#if IS_ENABLED(CONFIG_QPNP_USB_PDPHY)
int pd_phy_open(struct pd_phy_params *params);
int pd_phy_signal(enum pd_sig_type type, unsigned int timeout_ms);
int pd_phy_signal(enum pd_sig_type sig);
int pd_phy_write(u16 hdr, const u8 *data, size_t data_len,
	enum pd_msg_type type, unsigned int timeout_ms);
		enum pd_sop_type sop);
int pd_phy_update_roles(enum data_role dr, enum power_role pr);
void pd_phy_close(void);
#else
@@ -83,13 +83,13 @@ static inline int pd_phy_open(struct pd_phy_params *params)
	return -ENODEV;
}

static inline int pd_phy_signal(enum pd_sig_type type, unsigned int timeout_ms)
static inline int pd_phy_signal(enum pd_sig_type type)
{
	return -ENODEV;
}

static inline int pd_phy_write(u16 hdr, const u8 *data, size_t data_len,
	enum pd_msg_type type, unsigned int timeout_ms)
		enum pd_sop_type sop)
{
	return -ENODEV;
}