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

Commit 72336f60 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: pd: Don't retry sending Source Capabilities if PD capable"

parents 88c1fe37 7be40e05
Loading
Loading
Loading
Loading
+20 −45
Original line number Diff line number Diff line
@@ -373,34 +373,9 @@ static inline void dwc3_msm_write_reg_field(void __iomem *base, u32 offset,
	tmp &= ~mask;		/* clear written bits */
	val = tmp | (val << shift);
	iowrite32(val, base + offset);
}

/**
 * Write register and read back masked value to confirm it is written
 *
 * @base - DWC3 base virtual address.
 * @offset - register offset.
 * @mask - register bitmask specifying what should be updated
 * @val - value to write.
 *
 */
static inline void dwc3_msm_write_readback(void __iomem *base, u32 offset,
					    const u32 mask, u32 val)
{
	u32 write_val, tmp = ioread32(base + offset);

	tmp &= ~mask;		/* retain other bits */
	write_val = tmp | val;

	iowrite32(write_val, base + offset);

	/* Read back to see if val was written */
	tmp = ioread32(base + offset);
	tmp &= mask;		/* clear other bits */

	if (tmp != val)
		pr_err("%s: write: %x to QSCRATCH: %x FAILED\n",
			__func__, val, offset);
	/* Read back to make sure that previous write goes through */
	ioread32(base + offset);
}

static bool dwc3_msm_is_ss_rhport_connected(struct dwc3_msm *mdwc)
@@ -952,21 +927,24 @@ static void gsi_store_ringbase_dbl_info(struct usb_ep *ep,
		GSI_RING_BASE_ADDR_L(mdwc->gsi_reg[RING_BASE_ADDR_L], (n)),
		dwc3_trb_dma_offset(dep, &dep->trb_pool[0]));

	if (request->mapped_db_reg_phs_addr_lsb)
		dma_unmap_resource(dwc->sysdev,
			request->mapped_db_reg_phs_addr_lsb,
	if (!request->mapped_db_reg_phs_addr_lsb) {
		request->mapped_db_reg_phs_addr_lsb =
			dma_map_resource(dwc->sysdev,
				(phys_addr_t)request->db_reg_phs_addr_lsb,
				PAGE_SIZE, DMA_BIDIRECTIONAL, 0);

	request->mapped_db_reg_phs_addr_lsb = dma_map_resource(dwc->sysdev,
			(phys_addr_t)request->db_reg_phs_addr_lsb, PAGE_SIZE,
			DMA_BIDIRECTIONAL, 0);
	if (dma_mapping_error(dwc->sysdev, request->mapped_db_reg_phs_addr_lsb))
		if (dma_mapping_error(dwc->sysdev,
				request->mapped_db_reg_phs_addr_lsb))
			dev_err(mdwc->dev, "mapping error for db_reg_phs_addr_lsb\n");
	}

	dev_dbg(mdwc->dev, "ep:%s dbl_addr_lsb:%x mapped_dbl_addr_lsb:%llx\n",
		ep->name, request->db_reg_phs_addr_lsb,
		(unsigned long long)request->mapped_db_reg_phs_addr_lsb);

	dbg_log_string("ep:%s dbl_addr_lsb:%x mapped_addr:%llx\n",
		ep->name, request->db_reg_phs_addr_lsb,
		(unsigned long long)request->mapped_db_reg_phs_addr_lsb);

	dwc3_msm_write_reg(mdwc->base,
		GSI_DBL_ADDR_L(mdwc->gsi_reg[DBL_ADDR_L], (n)),
		(u32)request->mapped_db_reg_phs_addr_lsb);
@@ -4033,17 +4011,14 @@ static void dwc3_override_vbus_status(struct dwc3_msm *mdwc, bool vbus_present)
	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);

	/* Update OTG VBUS Valid from HSPHY to controller */
	dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
		vbus_present ? UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL :
		UTMI_OTG_VBUS_VALID,
		vbus_present ? UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL : 0);
	dwc3_msm_write_reg_field(mdwc->base, HS_PHY_CTRL_REG,
			UTMI_OTG_VBUS_VALID, !!vbus_present);

	/* Update only if Super Speed is supported */
	if (dwc->maximum_speed >= USB_SPEED_SUPER) {
		/* Update VBUS Valid from SSPHY to controller */
		dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG,
			LANE0_PWR_PRESENT,
			vbus_present ? LANE0_PWR_PRESENT : 0);
		dwc3_msm_write_reg_field(mdwc->base, SS_PHY_CTRL_REG,
			LANE0_PWR_PRESENT, !!vbus_present);
	}
}

@@ -4145,7 +4120,7 @@ static int dwc3_usb_blocking_sync(struct notifier_block *nb,

	dbg_event(0xFF, "fw_blocksync", 0);
	flush_work(&mdwc->resume_work);
	flush_delayed_work(&mdwc->sm_work);
	drain_workqueue(mdwc->sm_usb_wq);

	if (!mdwc->in_host_mode && !mdwc->in_device_mode) {
		dbg_event(0xFF, "lpm_state", atomic_read(&dwc->in_lpm));
+49 −32
Original line number Diff line number Diff line
@@ -230,7 +230,7 @@ static void *usbpd_ipc_log;
#define PS_HARD_RESET_TIME	25
#define PS_SOURCE_ON		400
#define PS_SOURCE_OFF		750
#define FIRST_SOURCE_CAP_TIME	200
#define FIRST_SOURCE_CAP_TIME	100
#define VDM_BUSY_TIME		50
#define VCONN_ON_TIME		100

@@ -344,8 +344,6 @@ static void *usbpd_ipc_log;
#define ID_HDR_PRODUCT_PER	2
#define ID_HDR_PRODUCT_AMA	5
#define ID_HDR_PRODUCT_VPD	6
#define ID_HDR_VID		0x05c6 /* qcom */
#define PROD_VDO_PID		0x0a00 /* TBD */

#define PD_MIN_SINK_CURRENT	900

@@ -668,14 +666,29 @@ static inline void pd_reset_protocol(struct usbpd *pd)
static int pd_send_msg(struct usbpd *pd, u8 msg_type, const u32 *data,
		size_t num_data, enum pd_sop_type sop)
{
	unsigned long flags;
	int ret;
	u16 hdr;

	if (pd->hard_reset_recvd)
		return -EBUSY;

	if (sop == SOP_MSG)
		hdr = PD_MSG_HDR(msg_type, pd->current_dr, pd->current_pr,
				pd->tx_msgid[sop], num_data, pd->spec_rev);
	else
		/* sending SOP'/SOP'' to a cable, PR/DR fields should be 0 */
		hdr = PD_MSG_HDR(msg_type, 0, 0, pd->tx_msgid[sop], num_data,
				pd->spec_rev);

	/* bail out and try again later if a message just arrived */
	spin_lock_irqsave(&pd->rx_lock, flags);
	if (!list_empty(&pd->rx_q)) {
		spin_unlock_irqrestore(&pd->rx_lock, flags);
		usbpd_dbg(&pd->dev, "Abort send due to pending RX\n");
		return -EBUSY;
	}
	spin_unlock_irqrestore(&pd->rx_lock, flags);

	ret = pd_phy_write(hdr, (u8 *)data, num_data * sizeof(u32), sop);
	if (ret) {
@@ -820,10 +833,6 @@ static int pd_eval_src_caps(struct usbpd *pd)
	power_supply_set_property(pd->usb_psy,
			POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED, &val);

	/* First time connecting to a PD source and it supports USB data */
	if (pd->peer_usb_comm && pd->current_dr == DR_UFP && !pd->pd_connected)
		start_usb_peripheral(pd);

	/* Check for PPS APDOs */
	if (pd->spec_rev == USBPD_REV_30) {
		for (i = 1; i < PD_MAX_DATA_OBJ; i++) {
@@ -846,6 +855,10 @@ static int pd_eval_src_caps(struct usbpd *pd)
	power_supply_set_property(pd->usb_psy,
			POWER_SUPPLY_PROP_PD_ACTIVE, &val);

	/* First time connecting to a PD source and it supports USB data */
	if (pd->peer_usb_comm && pd->current_dr == DR_UFP && !pd->pd_connected)
		start_usb_peripheral(pd);

	/* Select the first PDO (vSafe5V) immediately. */
	pd_select_pdo(pd, 1, 0, 0);

@@ -1452,18 +1465,7 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg)
	/* Standard Discovery or unhandled messages go here */
	switch (cmd_type) {
	case SVDM_CMD_TYPE_INITIATOR:
		if (svid == USBPD_SID && cmd == USBPD_SVDM_DISCOVER_IDENTITY) {
			u32 tx_vdos[3] = {
				ID_HDR_USB_HOST | ID_HDR_USB_DEVICE |
					ID_HDR_PRODUCT_PER_MASK | ID_HDR_VID,
				0x0, /* TBD: Cert Stat VDO */
				(PROD_VDO_PID << 16),
				/* TBD: Get these from gadget */
			};

			usbpd_send_svdm(pd, USBPD_SID, cmd,
					SVDM_CMD_TYPE_RESP_ACK, 0, tx_vdos, 3);
		} else if (cmd != USBPD_SVDM_ATTENTION) {
		if (cmd != USBPD_SVDM_ATTENTION) {
			usbpd_send_svdm(pd, svid, cmd, SVDM_CMD_TYPE_RESP_NAK,
					SVDM_HDR_OBJ_POS(vdm_hdr), NULL, 0);
		}
@@ -1509,20 +1511,11 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg)
static void handle_vdm_tx(struct usbpd *pd, enum pd_sop_type sop_type)
{
	int ret;
	unsigned long flags;

	/* only send one VDM at a time */
	if (pd->vdm_tx) {
		u32 vdm_hdr = pd->vdm_tx->data[0];

		/* bail out and try again later if a message just arrived */
		spin_lock_irqsave(&pd->rx_lock, flags);
		if (!list_empty(&pd->rx_q)) {
			spin_unlock_irqrestore(&pd->rx_lock, flags);
			return;
		}
		spin_unlock_irqrestore(&pd->rx_lock, flags);

		ret = pd_send_msg(pd, MSG_VDM, pd->vdm_tx->data,
				pd->vdm_tx->size, sop_type);
		if (ret) {
@@ -1598,6 +1591,9 @@ static void dr_swap(struct usbpd *pd)
			start_usb_host(pd, true);
		pd->current_dr = DR_DFP;

		/* ensure host is started before allowing DP */
		extcon_blocking_sync(pd->extcon, EXTCON_USB_HOST, 0);

		usbpd_send_svdm(pd, USBPD_SID, USBPD_SVDM_DISCOVER_IDENTITY,
				SVDM_CMD_TYPE_INITIATOR, 0, NULL, 0);
	}
@@ -1919,6 +1915,16 @@ static void handle_state_src_send_capabilities(struct usbpd *pd,
	ret = pd_send_msg(pd, MSG_SOURCE_CAPABILITIES, default_src_caps,
			ARRAY_SIZE(default_src_caps), SOP_MSG);
	if (ret) {
		if (pd->pd_connected) {
			usbpd_set_state(pd, PE_SEND_SOFT_RESET);
			break;
		}

		/*
		 * Technically this is PE_SRC_Discovery, but we can
		 * handle it by setting a timer to come back to the
		 * same state for the next retry.
		 */
		pd->caps_count++;
		if (pd->caps_count >= PD_CAPS_COUNT) {
			usbpd_dbg(&pd->dev, "Src CapsCounter exceeded, disabling PD\n");
@@ -2206,9 +2212,19 @@ static void enter_state_snk_startup(struct usbpd *pd)
	};
	union power_supply_propval val = {0};

	if (pd->current_dr == DR_NONE || pd->current_dr == DR_UFP)
	if (pd->current_dr == DR_NONE || pd->current_dr == DR_UFP) {
		pd->current_dr = DR_UFP;

		ret = power_supply_get_property(pd->usb_psy,
				POWER_SUPPLY_PROP_REAL_TYPE, &val);
		if (!ret) {
			usbpd_dbg(&pd->dev, "type:%d\n", val.intval);
			if (val.intval == POWER_SUPPLY_TYPE_USB ||
				val.intval == POWER_SUPPLY_TYPE_USB_CDP)
				start_usb_peripheral(pd);
		}
	}

	dual_role_instance_changed(pd->dual_role);

	/*
@@ -3186,7 +3202,8 @@ static void usbpd_sm(struct work_struct *w)

	/* Disconnect? */
	if (pd->current_pr == PR_NONE) {
		if (pd->current_state == PE_UNKNOWN)
		if (pd->current_state == PE_UNKNOWN &&
				pd->current_dr == DR_NONE)
			goto sm_done;

		handle_disconnect(pd);
+9 −1
Original line number Diff line number Diff line
@@ -473,13 +473,16 @@ 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;
	struct usb_pdphy *pdphy = __pdphy;
	unsigned int msg_rx_cnt;

	if (!pdphy) {
		pr_err("%s: pdphy not found\n", __func__);
		return -ENODEV;
	}

	msg_rx_cnt = pdphy->msg_rx_cnt;

	if (!pdphy->is_opened) {
		dev_dbg(pdphy->dev, "%s: pdphy disabled\n", __func__);
		return -ENODEV;
@@ -537,6 +540,11 @@ int pd_phy_write(u16 hdr, const u8 *data, size_t data_len, enum pd_sop_type sop)
	else
		val |= TX_CONTROL_RETRY_COUNT(3);

	if (msg_rx_cnt != pdphy->msg_rx_cnt) {
		dev_err(pdphy->dev, "%s: RX message arrived\n", __func__);
		return -EBUSY;
	}

	ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, val);
	if (ret)
		return ret;
+111 −14
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#include <linux/regulator/consumer.h>
#include <linux/usb/phy.h>
#include <linux/clk.h>
#include <linux/extcon.h>
#include <linux/reset.h>
#include <linux/hrtimer.h>

@@ -70,6 +71,7 @@ enum core_ldo_levels {
/* USB3_DP_COM_PHY_MODE_CTRL bits */
#define USB3_MODE		BIT(0) /* enables USB3 mode */
#define DP_MODE			BIT(1) /* enables DP mode */
#define USB3_DP_COMBO_MODE	(USB3_MODE | DP_MODE) /*enables combo mode */

/* USB3 Gen2 link training indicator */
#define RX_EQUALIZATION_IN_PROGRESS	BIT(3)
@@ -82,6 +84,9 @@ enum qmp_phy_rev_reg {
	USB3_PHY_SW_RESET,
	USB3_PHY_START,

	/* TypeC port select configuration (optional) */
	USB3_PHY_PCS_MISC_TYPEC_CTRL,

	/* USB DP Combo PHY related */
	USB3_DP_DP_PHY_PD_CTL,
	USB3_DP_COM_POWER_DOWN_CTRL,
@@ -94,8 +99,6 @@ enum qmp_phy_rev_reg {
	USB3_DP_PCS_PCS_STATUS2,
	USB3_DP_PCS_INSIG_SW_CTRL3,
	USB3_DP_PCS_INSIG_MX_CTRL3,
	/* TypeC port select configuration (optional) */
	USB3_PHY_PCS_MISC_TYPEC_CTRL,
	USB3_PHY_REG_MAX,
};

@@ -126,6 +129,8 @@ struct msm_ssphy_qmp {
	struct reset_control	*phy_reset;
	struct reset_control	*phy_phy_reset;
	struct reset_control	*global_phy_reset;
	struct extcon_dev	*extcon_dp;
	struct notifier_block	dp_nb;
	bool			power_enabled;
	bool			clk_enabled;
	bool			cable_connected;
@@ -335,6 +340,18 @@ static int configure_phy_regs(struct usb_phy *uphy,
	return 0;
}

static void msm_ssphy_qmp_setmode(struct msm_ssphy_qmp *phy, u32 mode)
{
	mode = mode & USB3_DP_COMBO_MODE;

	writel_relaxed(mode,
			phy->base + phy->phy_reg[USB3_DP_COM_PHY_MODE_CTRL]);

	/* flush the write by reading it */
	readl_relaxed(phy->base + phy->phy_reg[USB3_DP_COM_PHY_MODE_CTRL]);
}


static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy)
{
	int val;
@@ -352,9 +369,11 @@ static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy)
	switch (phy->phy.type) {
	case USB_PHY_TYPE_USB3_AND_DP:
		/* override hardware control for reset of qmp phy */
		if (!(phy->phy.flags & PHY_USB_DP_CONCURRENT_MODE))
			writel_relaxed(SW_DPPHY_RESET_MUX | SW_DPPHY_RESET |
				SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET,
			phy->base + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]);
				phy->base +
				phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]);

		/* update port select */
		if (val > 0) {
@@ -364,12 +383,13 @@ static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy)
				phy->phy_reg[USB3_DP_COM_TYPEC_CTRL]);
		}

		writel_relaxed(USB3_MODE | DP_MODE,
			phy->base + phy->phy_reg[USB3_DP_COM_PHY_MODE_CTRL]);
		if (!(phy->phy.flags & PHY_USB_DP_CONCURRENT_MODE)) {
			msm_ssphy_qmp_setmode(phy, USB3_DP_COMBO_MODE);

		/* bring both QMP USB and QMP DP PHYs PCS block out of reset */
		writel_relaxed(0x00,
			phy->base + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]);
			/* bring both USB and DP PHYs PCS block out of reset */
			writel_relaxed(0x00, phy->base +
				phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]);
		}
		break;
	case  USB_PHY_TYPE_USB3_OR_DP:
		if (val > 0) {
@@ -457,7 +477,8 @@ static int msm_ssphy_qmp_init(struct usb_phy *uphy)
	}

	/* perform software reset of PHY common logic */
	if (phy->phy.type == USB_PHY_TYPE_USB3_AND_DP)
	if (phy->phy.type == USB_PHY_TYPE_USB3_AND_DP &&
				!(phy->phy.flags & PHY_USB_DP_CONCURRENT_MODE))
		writel_relaxed(0x00,
			phy->base + phy->phy_reg[USB3_DP_COM_SW_RESET]);

@@ -495,6 +516,25 @@ static int msm_ssphy_qmp_dp_combo_reset(struct usb_phy *uphy)
					phy);
	int ret = 0;

	if (phy->phy.flags & PHY_USB_DP_CONCURRENT_MODE) {
		dev_dbg(uphy->dev, "Resetting USB part of QMP phy\n");

		/* Assert USB3 PHY CSR reset */
		ret = reset_control_assert(phy->phy_reset);
		if (ret) {
			dev_err(uphy->dev, "phy_reset assert failed\n");
			goto exit;
		}

		/* Deassert USB3 PHY CSR reset */
		ret = reset_control_deassert(phy->phy_reset);
		if (ret) {
			dev_err(uphy->dev, "phy_reset deassert failed\n");
			goto exit;
		}
		return 0;
	}

	dev_dbg(uphy->dev, "Global reset of QMP DP combo phy\n");
	/* Assert global PHY reset */
	ret = reset_control_assert(phy->global_phy_reset);
@@ -627,11 +667,14 @@ static int msm_ssphy_qmp_set_suspend(struct usb_phy *uphy, int suspend)
	}

	if (suspend) {
		if (phy->cable_connected)
		if (phy->cable_connected) {
			msm_ssusb_qmp_enable_autonomous(phy, 1);
		else
		} else {
			if (uphy->type  == USB_PHY_TYPE_USB3_AND_DP)
				msm_ssphy_qmp_setmode(phy, USB3_MODE);
			writel_relaxed(0x00,
			phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]);
		}

		/* Make sure above write completed with PHY */
		wmb();
@@ -758,6 +801,56 @@ static int msm_ssphy_qmp_notify_disconnect(struct usb_phy *uphy,
	return 0;
}

static int msm_ssphy_qmp_vbus_notifier(struct notifier_block *nb,
		unsigned long event, void *ptr)
{
	return 0;
}

static int msm_ssphy_qmp_dp_notifier(struct notifier_block *nb,
		unsigned long dp_lane, void *ptr)
{
	struct msm_ssphy_qmp *phy = container_of(nb,
			struct msm_ssphy_qmp, dp_nb);

	if (dp_lane == 2 || dp_lane == 4)
		phy->phy.flags |= PHY_USB_DP_CONCURRENT_MODE;
	else
		phy->phy.flags &= ~PHY_USB_DP_CONCURRENT_MODE;

	return 0;

}

static int msm_ssphy_qmp_extcon_register(struct msm_ssphy_qmp *phy,
				struct device *dev)
{
	struct device_node *node = dev->of_node;
	struct extcon_dev *edev;
	int ret = 0;

	if (!of_property_read_bool(node, "extcon"))
		return 0;

	edev = extcon_get_edev_by_phandle(dev, 0);
	if (IS_ERR(edev)) {
		dev_err(dev, "failed to get phandle for msm_ssphy_qmp\n");
		return PTR_ERR(edev);
	}

	phy->extcon_dp = edev;
	phy->phy.vbus_nb.notifier_call = msm_ssphy_qmp_vbus_notifier;
	phy->dp_nb.notifier_call = msm_ssphy_qmp_dp_notifier;
	ret = extcon_register_blocking_notifier(edev, EXTCON_DISP_DP,
								&phy->dp_nb);
	if (ret < 0) {
		dev_err(dev, "failed to register blocking notifier\n");
		return ret;
	}

	return 0;
}

static int msm_ssphy_qmp_get_clks(struct msm_ssphy_qmp *phy, struct device *dev)
{
	int ret = 0;
@@ -877,7 +970,7 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev)
		phy->phy.type = USB_PHY_TYPE_USB3_AND_DP;

	if (of_device_is_compatible(dev->of_node,
			"qcom,usb-ssphy-qmp-usb-or-dp"))
			"qcom,usb-ssphy-qmp-usb3-or-dp"))
		phy->phy.type = USB_PHY_TYPE_USB3_OR_DP;

	ret = msm_ssphy_qmp_get_clks(phy, dev);
@@ -1069,6 +1162,10 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev)
	else
		phy->phy.reset		= msm_ssphy_qmp_reset;

	ret = msm_ssphy_qmp_extcon_register(phy, dev);
	if (ret)
		goto err;

	ret = usb_add_phy_dev(&phy->phy);

err:
+1 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#define PHY_LANE_B		BIT(7)
#define PHY_HSFS_MODE		BIT(8)
#define PHY_LS_MODE		BIT(9)
#define PHY_USB_DP_CONCURRENT_MODE	BIT(10)

enum usb_phy_interface {
	USBPHY_INTERFACE_MODE_UNKNOWN,