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

Commit bd641c5b 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: Improve timing accuracy"

parents f4bdb944 a8967b29
Loading
Loading
Loading
Loading
+81 −67
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
 */

#include <linux/delay.h>
#include <linux/hrtimer.h>
#include <linux/ipc_logging.h>
#include <linux/kernel.h>
#include <linux/list.h>
@@ -158,14 +159,15 @@ static void *usbpd_ipc_log;

/* Timeouts (in ms) */
#define ERROR_RECOVERY_TIME	25
#define SENDER_RESPONSE_TIME	30
#define SENDER_RESPONSE_TIME	26
#define SINK_WAIT_CAP_TIME	620
#define PS_TRANSITION_TIME	550
#define PS_TRANSITION_TIME	450
#define SRC_CAP_TIME		120
#define SRC_TRANSITION_TIME	25
#define PS_HARD_RESET_TIME	35
#define SRC_RECOVER_TIME	660
#define PS_HARD_RESET_TIME	25
#define PS_SOURCE_ON		400
#define PS_SOURCE_OFF		900
#define PS_SOURCE_OFF		750
#define VDM_BUSY_TIME		50

#define PD_CAPS_COUNT		50
@@ -255,7 +257,8 @@ struct vdm_tx {
struct usbpd {
	struct device		dev;
	struct workqueue_struct	*wq;
	struct delayed_work	sm_work;
	struct work_struct	sm_work;
	struct hrtimer		timer;

	struct extcon_dev	*extcon;

@@ -483,7 +486,7 @@ static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type)
	/* Force CC logic to source/sink to keep Rp/Rd unchanged */
	set_power_role(pd, pd->current_pr);
	pd->hard_reset = true;
	mod_delayed_work(pd->wq, &pd->sm_work, 0);
	queue_work(pd->wq, &pd->sm_work);
}

static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type,
@@ -531,7 +534,7 @@ static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type,
	pd->rx_msg_len = PD_MSG_HDR_COUNT(header);
	memcpy(&pd->rx_payload, buf, len);

	mod_delayed_work(pd->wq, &pd->sm_work, 0);
	queue_work(pd->wq, &pd->sm_work);
}

static void phy_shutdown(struct usbpd *pd)
@@ -539,6 +542,16 @@ static void phy_shutdown(struct usbpd *pd)
	usbpd_dbg(&pd->dev, "shutdown");
}

static enum hrtimer_restart pd_timeout(struct hrtimer *timer)
{
	struct usbpd *pd = container_of(timer, struct usbpd, timer);

	usbpd_dbg(&pd->dev, "timeout");
	queue_work(pd->wq, &pd->sm_work);

	return HRTIMER_NORESTART;
}

/* Enters new state and executes actions on entry */
static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
{
@@ -562,8 +575,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
	case PE_ERROR_RECOVERY: /* perform hard disconnect/reconnect */
		pd->in_pr_swap = false;
		set_power_role(pd, PR_NONE);
		queue_delayed_work(pd->wq, &pd->sm_work,
				msecs_to_jiffies(ERROR_RECOVERY_TIME));
		hrtimer_start(&pd->timer, ms_to_ktime(ERROR_RECOVERY_TIME),
				HRTIMER_MODE_REL);
		break;

	/* Source states */
@@ -609,7 +622,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
		/* fall-through */

	case PE_SRC_SEND_CAPABILITIES:
		queue_delayed_work(pd->wq, &pd->sm_work, 0);
		queue_work(pd->wq, &pd->sm_work);
		break;

	case PE_SRC_NEGOTIATE_CAPABILITY:
@@ -636,16 +649,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
			break;
		}

		/*
		 * we only support VSafe5V so Aceept right away as there is
		 * nothing more to prepare from the power supply
		 */
		pd->current_state = PE_SRC_TRANSITION_SUPPLY;
		usbpd_dbg(&pd->dev, "Enter %s\n",
				usbpd_state_strings[pd->current_state]);
		/* fall-through */

	case PE_SRC_TRANSITION_SUPPLY:
		/* PE_SRC_TRANSITION_SUPPLY pseudo-state */
		ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG);
		if (ret) {
			usbpd_err(&pd->dev, "Error sending Accept\n");
@@ -653,8 +657,23 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
			break;
		}

		queue_delayed_work(pd->wq, &pd->sm_work,
				msecs_to_jiffies(SRC_TRANSITION_TIME));
		/* tSrcTransition required after ACCEPT */
		usleep_range(SRC_TRANSITION_TIME * USEC_PER_MSEC,
				(SRC_TRANSITION_TIME + 5) * USEC_PER_MSEC);

		/*
		 * Normally a voltage change should occur within tSrcReady
		 * but since we only support VSafe5V there is nothing more to
		 * prepare from the power supply so send PS_RDY right away.
		 */
		ret = pd_send_msg(pd, MSG_PS_RDY, NULL, 0, SOP_MSG);
		if (ret) {
			usbpd_err(&pd->dev, "Error sending PS_RDY\n");
			usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
			break;
		}

		usbpd_set_state(pd, PE_SRC_READY);
		break;

	case PE_SRC_READY:
@@ -683,7 +702,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
			pd_phy_update_roles(pd->current_dr, pd->current_pr);
		}

		msleep(1000);	/* tSrcRecover */
		msleep(SRC_RECOVER_TIME);

		ret = regulator_enable(pd->vbus);
		if (ret)
@@ -703,7 +722,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
	case PE_SRC_HARD_RESET:
	case PE_SNK_HARD_RESET:
		/* hard reset may sleep; handle it in the workqueue */
		queue_delayed_work(pd->wq, &pd->sm_work, 0);
		queue_work(pd->wq, &pd->sm_work);
		break;

	case PE_SRC_SEND_SOFT_RESET:
@@ -721,8 +740,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
		}

		/* wait for ACCEPT */
		queue_delayed_work(pd->wq, &pd->sm_work,
				msecs_to_jiffies(SENDER_RESPONSE_TIME * 3));
		hrtimer_start(&pd->timer, ms_to_ktime(SENDER_RESPONSE_TIME),
				HRTIMER_MODE_REL);
		break;

	/* Sink states */
@@ -771,8 +790,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
		if (!pd->vbus_present) {
			/* can get here during a hard reset and we lost vbus */
			pd->current_state = PE_SNK_DISCOVERY;
			queue_delayed_work(pd->wq, &pd->sm_work,
					msecs_to_jiffies(2000));
			hrtimer_start(&pd->timer, ms_to_ktime(2000),
					HRTIMER_MODE_REL);
			break;
		}

@@ -785,10 +804,11 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)

	case PE_SNK_WAIT_FOR_CAPABILITIES:
		if (pd->rx_msg_len && pd->rx_msg_type)
			queue_delayed_work(pd->wq, &pd->sm_work, 0);
			queue_work(pd->wq, &pd->sm_work);
		else
			queue_delayed_work(pd->wq, &pd->sm_work,
				msecs_to_jiffies(SINK_WAIT_CAP_TIME));
			hrtimer_start(&pd->timer,
					ms_to_ktime(SINK_WAIT_CAP_TIME),
					HRTIMER_MODE_REL);
		break;

	case PE_SNK_EVALUATE_CAPABILITY:
@@ -810,14 +830,14 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
			usbpd_err(&pd->dev, "Error sending Request\n");

		/* wait for ACCEPT */
		queue_delayed_work(pd->wq, &pd->sm_work,
				msecs_to_jiffies(SENDER_RESPONSE_TIME * 3));
		hrtimer_start(&pd->timer, ms_to_ktime(SENDER_RESPONSE_TIME),
				HRTIMER_MODE_REL);
		break;

	case PE_SNK_TRANSITION_SINK:
		/* wait for PS_RDY */
		queue_delayed_work(pd->wq, &pd->sm_work,
				msecs_to_jiffies(PS_TRANSITION_TIME));
		hrtimer_start(&pd->timer, ms_to_ktime(PS_TRANSITION_TIME),
				HRTIMER_MODE_REL);
		break;

	case PE_SNK_READY:
@@ -910,7 +930,7 @@ int usbpd_send_vdm(struct usbpd *pd, u32 vdm_hdr, const u32 *vdos, int num_vdos)

	/* VDM will get sent in PE_SRC/SNK_READY state handling */
	list_add_tail(&vdm_tx->entry, &pd->vdm_tx_queue);
	queue_delayed_work(pd->wq, &pd->sm_work, 0);
	queue_work(pd->wq, &pd->sm_work);

	return 0;
}
@@ -1092,8 +1112,8 @@ static void handle_vdm_rx(struct usbpd *pd)
			/* wait tVDMBusy, then retry */
			list_move(&pd->vdm_tx_retry->entry, &pd->vdm_tx_queue);
			pd->vdm_tx_retry = NULL;
			queue_delayed_work(pd->wq, &pd->sm_work,
					msecs_to_jiffies(VDM_BUSY_TIME));
			hrtimer_start(&pd->timer, ms_to_ktime(VDM_BUSY_TIME),
					HRTIMER_MODE_REL);
			break;
		default:
			break;
@@ -1195,7 +1215,7 @@ static void dr_swap(struct usbpd *pd)
/* Handles current state and determines transitions */
static void usbpd_sm(struct work_struct *w)
{
	struct usbpd *pd = container_of(w, struct usbpd, sm_work.work);
	struct usbpd *pd = container_of(w, struct usbpd, sm_work);
	union power_supply_propval val = {0};
	int ret;
	enum usbpd_control_msg_type ctrl_recvd = 0;
@@ -1204,6 +1224,8 @@ static void usbpd_sm(struct work_struct *w)
	usbpd_dbg(&pd->dev, "handle state %s\n",
			usbpd_state_strings[pd->current_state]);

	hrtimer_cancel(&pd->timer);

	if (pd->rx_msg_len)
		data_recvd = pd->rx_msg_type;
	else
@@ -1325,8 +1347,8 @@ static void usbpd_sm(struct work_struct *w)
				break;
			}

			queue_delayed_work(pd->wq, &pd->sm_work,
					msecs_to_jiffies(SRC_CAP_TIME));
			hrtimer_start(&pd->timer, ms_to_ktime(SRC_CAP_TIME),
					HRTIMER_MODE_REL);
			break;
		}

@@ -1341,8 +1363,8 @@ static void usbpd_sm(struct work_struct *w)

		/* wait for REQUEST */
		pd->current_state = PE_SRC_SEND_CAPABILITIES_WAIT;
		queue_delayed_work(pd->wq, &pd->sm_work,
				msecs_to_jiffies(SENDER_RESPONSE_TIME * 3));
		hrtimer_start(&pd->timer, ms_to_ktime(SENDER_RESPONSE_TIME),
				HRTIMER_MODE_REL);
		break;

	case PE_SRC_SEND_CAPABILITIES_WAIT:
@@ -1354,17 +1376,6 @@ static void usbpd_sm(struct work_struct *w)
		}
		break;

	case PE_SRC_TRANSITION_SUPPLY:
		ret = pd_send_msg(pd, MSG_PS_RDY, NULL, 0, SOP_MSG);
		if (ret) {
			usbpd_err(&pd->dev, "Error sending PS_RDY\n");
			usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
			break;
		}

		usbpd_set_state(pd, PE_SRC_READY);
		break;

	case PE_SRC_READY:
		if (ctrl_recvd == MSG_GET_SOURCE_CAP) {
			ret = pd_send_msg(pd, MSG_SOURCE_CAPABILITIES,
@@ -1403,7 +1414,7 @@ static void usbpd_sm(struct work_struct *w)
			}

			pd->current_state = PE_PRS_SRC_SNK_TRANSITION_TO_OFF;
			queue_delayed_work(pd->wq, &pd->sm_work, 0);
			queue_work(pd->wq, &pd->sm_work);
			break;
		} else {
			if (data_recvd == MSG_VDM)
@@ -1418,7 +1429,8 @@ static void usbpd_sm(struct work_struct *w)
		pd->in_explicit_contract = false;
		reset_vdm_state(pd);

		msleep(PS_HARD_RESET_TIME);
		usleep_range(PS_HARD_RESET_TIME * USEC_PER_MSEC,
				(PS_HARD_RESET_TIME + 5) * USEC_PER_MSEC);
		usbpd_set_state(pd, PE_SRC_TRANSITION_TO_DEFAULT);
		break;

@@ -1429,7 +1441,7 @@ static void usbpd_sm(struct work_struct *w)
					POWER_SUPPLY_PROP_TYPE, &val);
			if (val.intval == POWER_SUPPLY_TYPEC_NONE) {
				pd->typec_mode = POWER_SUPPLY_TYPEC_NONE;
				queue_delayed_work(pd->wq, &pd->sm_work, 0);
				queue_work(pd->wq, &pd->sm_work);
			}
			break;
		}
@@ -1557,8 +1569,8 @@ static void usbpd_sm(struct work_struct *w)
			pd->current_pr = PR_SRC;
			pd_phy_update_roles(pd->current_dr, pd->current_pr);

			queue_delayed_work(pd->wq, &pd->sm_work,
					msecs_to_jiffies(PS_SOURCE_OFF));
			hrtimer_start(&pd->timer, ms_to_ktime(PS_SOURCE_OFF),
					HRTIMER_MODE_REL);
			break;
		} else {
			if (data_recvd == MSG_VDM)
@@ -1659,8 +1671,8 @@ static void usbpd_sm(struct work_struct *w)
		}

		pd->current_state = PE_PRS_SRC_SNK_WAIT_SOURCE_ON;
		queue_delayed_work(pd->wq, &pd->sm_work,
				msecs_to_jiffies(PS_SOURCE_ON));
		hrtimer_start(&pd->timer, ms_to_ktime(PS_SOURCE_ON),
				HRTIMER_MODE_REL);
		break;

	case PE_PRS_SRC_SNK_WAIT_SOURCE_ON:
@@ -1688,8 +1700,8 @@ static void usbpd_sm(struct work_struct *w)
		pd->current_pr = PR_SRC;
		pd_phy_update_roles(pd->current_dr, pd->current_pr);

		queue_delayed_work(pd->wq, &pd->sm_work,
				msecs_to_jiffies(PS_SOURCE_OFF));
		hrtimer_start(&pd->timer, ms_to_ktime(PS_SOURCE_OFF),
				HRTIMER_MODE_REL);
		break;

	case PE_PRS_SNK_SRC_TRANSITION_TO_OFF:
@@ -1819,7 +1831,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
	switch (typec_mode) {
	/* Disconnect */
	case POWER_SUPPLY_TYPEC_NONE:
		queue_delayed_work(pd->wq, &pd->sm_work, 0);
		queue_work(pd->wq, &pd->sm_work);
		break;

	/* Sink states */
@@ -1829,7 +1841,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
		usbpd_info(&pd->dev, "Type-C Source connected\n");
		if (pd->current_pr != PR_SINK) {
			pd->current_pr = PR_SINK;
			queue_delayed_work(pd->wq, &pd->sm_work, 0);
			queue_work(pd->wq, &pd->sm_work);
		}
		break;

@@ -1839,7 +1851,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
		usbpd_info(&pd->dev, "Type-C Sink connected\n");
		if (pd->current_pr != PR_SRC) {
			pd->current_pr = PR_SRC;
			queue_delayed_work(pd->wq, &pd->sm_work, 0);
			queue_work(pd->wq, &pd->sm_work);
		}
		break;

@@ -2282,7 +2294,9 @@ struct usbpd *usbpd_create(struct device *parent)
		ret = -ENOMEM;
		goto del_pd;
	}
	INIT_DELAYED_WORK(&pd->sm_work, usbpd_sm);
	INIT_WORK(&pd->sm_work, usbpd_sm);
	hrtimer_init(&pd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	pd->timer.function = pd_timeout;

	pd->usb_psy = power_supply_get_by_name("usb");
	if (!pd->usb_psy) {
+49 −13
Original line number Diff line number Diff line
@@ -58,6 +58,12 @@
#define USB_PDPHY_RX_ACKNOWLEDGE	0x4B
#define RX_BUFFER_TOKEN			BIT(0)

#define USB_PDPHY_BIST_MODE		0x4E
#define BIST_MODE_MASK			0xF
#define BIST_ENABLE			BIT(7)
#define PD_MSG_BIST			0x3
#define PD_BIST_TEST_DATA_MODE		0x8

#define USB_PDPHY_TX_BUFFER_HDR		0x60
#define USB_PDPHY_TX_BUFFER_DATA	0x62

@@ -95,6 +101,7 @@ struct usb_pdphy {
	bool is_opened;
	int tx_status;
	u8 frame_filter_val;
	bool in_test_data_mode;

	enum data_role data_role;
	enum power_role power_role;
@@ -233,6 +240,7 @@ void pdphy_enable_irq(struct usb_pdphy *pdphy, bool enable)
		enable_irq(pdphy->sig_tx_irq);
		enable_irq(pdphy->sig_rx_irq);
		enable_irq(pdphy->msg_tx_irq);
		if (!pdphy->in_test_data_mode)
			enable_irq(pdphy->msg_rx_irq);
		enable_irq(pdphy->msg_tx_failed_irq);
		enable_irq(pdphy->msg_tx_discarded_irq);
@@ -243,6 +251,7 @@ void pdphy_enable_irq(struct usb_pdphy *pdphy, bool enable)
	disable_irq(pdphy->sig_tx_irq);
	disable_irq(pdphy->sig_rx_irq);
	disable_irq(pdphy->msg_tx_irq);
	if (!pdphy->in_test_data_mode)
		disable_irq(pdphy->msg_rx_irq);
	disable_irq(pdphy->msg_tx_failed_irq);
	disable_irq(pdphy->msg_tx_discarded_irq);
@@ -523,6 +532,9 @@ void pd_phy_close(void)

	wake_up_all(&pdphy->tx_waitq);

	pdphy_reg_write(pdphy, USB_PDPHY_BIST_MODE, 0);
	pdphy->in_test_data_mode = false;

	ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, 0);
	if (ret)
		return;
@@ -600,6 +612,9 @@ static irqreturn_t pdphy_sig_tx_irq_thread(int irq, void *data)
{
	struct usb_pdphy *pdphy = data;

	/* in case of exit from BIST Carrier Mode 2, clear BIST_MODE */
	pdphy_reg_write(pdphy, USB_PDPHY_BIST_MODE, 0);

	pdphy->sig_tx_cnt++;
	pdphy->tx_status = 0;
	wake_up(&pdphy->tx_waitq);
@@ -607,10 +622,24 @@ static irqreturn_t pdphy_sig_tx_irq_thread(int irq, void *data)
	return IRQ_HANDLED;
}

static int pd_phy_bist_mode(u8 bist_mode)
{
	struct usb_pdphy *pdphy = __pdphy;

	dev_dbg(pdphy->dev, "%s: enter BIST mode %d\n", __func__, bist_mode);

	pdphy_reg_write(pdphy, USB_PDPHY_BIST_MODE, 0);

	udelay(5);

	return pdphy_masked_write(pdphy, USB_PDPHY_BIST_MODE,
			BIST_MODE_MASK | BIST_ENABLE, bist_mode | BIST_ENABLE);
}

static irqreturn_t pdphy_msg_rx_irq_thread(int irq, void *data)
{
	u8 size, rx_status, frame_type;
	u8 *buf = NULL;
	u8 buf[32];
	int ret;
	struct usb_pdphy *pdphy = data;

@@ -620,9 +649,8 @@ static irqreturn_t pdphy_msg_rx_irq_thread(int irq, void *data)
	if (ret)
		goto done;

	if (!size) {
		dev_err(pdphy->dev, "%s: incorrect size 1byte\n",
			__func__);
	if (!size || size > 31) {
		dev_err(pdphy->dev, "%s: invalid size %d\n", __func__, size);
		goto done;
	}

@@ -637,25 +665,33 @@ static irqreturn_t pdphy_msg_rx_irq_thread(int irq, void *data)
		goto done;
	}

	buf = kmalloc(size + 1, GFP_KERNEL);
	if (!buf)
		goto done;

	ret = pdphy_reg_read(pdphy, buf, USB_PDPHY_RX_BUFFER, size + 1);
	if (ret)
		goto done;

	/* ack to change ownership of rx buffer back to PDPHY RX HW */
	if (((buf[0] & 0xf) == PD_MSG_BIST) && size >= 5) { /* BIST */
		u8 mode = buf[5] >> 4; /* [31:28] of 1st data object */

		pd_phy_bist_mode(mode);
		pdphy_reg_write(pdphy, USB_PDPHY_RX_ACKNOWLEDGE, 0);

		if (mode == PD_BIST_TEST_DATA_MODE) {
			pdphy->in_test_data_mode = true;
			disable_irq_nosync(irq);
		}
		goto done;
	}

	if (pdphy->msg_rx_cb)
		pdphy->msg_rx_cb(pdphy->usbpd, frame_type, buf, size + 1);

	/* ack to change ownership of rx buffer back to PDPHY RX HW */
	pdphy_reg_write(pdphy, USB_PDPHY_RX_ACKNOWLEDGE, 0);

	print_hex_dump_debug("rx msg:", DUMP_PREFIX_NONE, 32, 4, buf, size + 1,
		false);
	pdphy->rx_bytes += size + 1;
done:
	kfree(buf);
	return IRQ_HANDLED;
}