Re: [PATCH v2 03/10] usb: tcpm: add lightweight PD negotiation tracing

Sebastian Reichel <[email protected]>
Newsgroups gmane.comp.boot-loaders.u-boot.general,gmane.comp.boot-loaders.u-boot
Message-ID <anei1Vtzhv-yxi-J@venus>
Hi,

On Sun, Jun 21, 2026 at 10:06:39AM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <[email protected]>
> 
> Add a zero-overhead ring buffer trace facility for debugging USB PD
> negotiation timing issues. Trace points record timestamp and event
> to a RAM buffer without any serial output, avoiding interference
> with PD protocol timing constraints.
> 
> Trace points cover the critical PD sink negotiation path:
> - Source_Capabilities reception
> - Request construction and transmission
> - TX completion polling
> - Accept/PS_RDY reception
> - SNK_READY state entry
> - Post-ready polling
> 
> The trace buffer can be dumped on demand via pd_trace_dump() for
> post-mortem analysis of PD negotiation failures.
> 
> Signed-off-by: Peng Fan <[email protected]>
> ---

The functionality looks sensible, but there is no user. I think it
would be sensible to add a new sub-function running pd_trace_dump()
to cmd/tcpm.c.

Greetings,

-- Sebastian

>  drivers/usb/tcpm/tcpm-internal.h | 40 ++++++++++++++++++++++++++++++++++++++++
>  drivers/usb/tcpm/tcpm.c          | 17 +++++++++++++++++
>  2 files changed, 57 insertions(+)
> 
> diff --git a/drivers/usb/tcpm/tcpm-internal.h b/drivers/usb/tcpm/tcpm-internal.h
> index 56144209002..138b0dc089e 100644
> --- a/drivers/usb/tcpm/tcpm-internal.h
> +++ b/drivers/usb/tcpm/tcpm-internal.h
> @@ -166,6 +166,46 @@ struct tcpm_port {
>  	unsigned long delay_target;
>  };
>  
> +#define PD_TRACE_MAX 32
> +
> +struct pd_trace_entry {
> +	unsigned long ts_us;
> +	const char *event;
> +	u32 val;
> +};
> +
> +struct pd_trace_buf {
> +	struct pd_trace_entry entries[PD_TRACE_MAX];
> +	int count;
> +};
> +
> +extern struct pd_trace_buf g_pd_trace;
> +
> +static inline void pd_trace(const char *event, u32 val)
> +{
> +	if (g_pd_trace.count < PD_TRACE_MAX) {
> +		struct pd_trace_entry *e = &g_pd_trace.entries[g_pd_trace.count++];
> +
> +		e->ts_us = timer_get_us();
> +		e->event = event;
> +		e->val = val;
> +	}
> +}
> +
> +static inline void pd_trace_dump(void)
> +{
> +	int i;
> +	unsigned long base = g_pd_trace.count > 0 ? g_pd_trace.entries[0].ts_us : 0;
> +
> +	printf("=== PD TRACE (%d entries) ===\n", g_pd_trace.count);
> +	for (i = 0; i < g_pd_trace.count; i++) {
> +		struct pd_trace_entry *e = &g_pd_trace.entries[i];
> +
> +		printf("[+%7luus] %-30s 0x%08x\n",
> +		       e->ts_us - base, e->event, e->val);
> +	}
> +}
> +
>  extern const char * const tcpm_states[];
>  
>  int tcpm_post_probe(struct udevice *dev);
> diff --git a/drivers/usb/tcpm/tcpm.c b/drivers/usb/tcpm/tcpm.c
> index d6af0fae7c1..1ce46118fea 100644
> --- a/drivers/usb/tcpm/tcpm.c
> +++ b/drivers/usb/tcpm/tcpm.c
> @@ -23,6 +23,8 @@ const char * const tcpm_states[] = {
>  	FOREACH_TCPM_STATE(GENERATE_TCPM_STRING)
>  };
>  
> +struct pd_trace_buf g_pd_trace;
> +
>  const char * const typec_pd_rev_name[] = {
>  	[PD_REV10]		= "rev1",
>  	[PD_REV20]		= "rev2",
> @@ -193,7 +195,9 @@ static int tcpm_pd_transmit(struct udevice *dev,
>  		dev_dbg(dev, "TCPM: PD TX, type: %#x\n", type);
>  
>  	port->tx_complete = false;
> +	pd_trace("PD_TX_START", type);
>  	ret = drvops->pd_transmit(dev, type, msg, port->negotiated_rev);
> +	pd_trace("PD_TX_DONE", ret);
>  	if (ret < 0)
>  		return ret;
>  
> @@ -213,6 +217,7 @@ static int tcpm_pd_transmit(struct udevice *dev,
>  		return ret;
>  	}
>  
> +	pd_trace("TX_POLL_DONE", port->tx_status);
>  	switch (port->tx_status) {
>  	case TCPC_TX_SUCCESS:
>  		port->message_id = (port->message_id + 1) & PD_HEADER_ID_MASK;
> @@ -626,6 +631,7 @@ static void tcpm_pd_data_request(struct udevice *dev,
>  
>  	switch (type) {
>  	case PD_DATA_SOURCE_CAP:
> +		pd_trace("RX_SOURCE_CAP", cnt);
>  		for (i = 0; i < cnt; i++)
>  			port->source_caps[i] = le32_to_cpu(msg->payload[i]);
>  
> @@ -668,6 +674,7 @@ static void tcpm_pd_data_request(struct udevice *dev,
>  		 * but be prepared to keep waiting for VBUS after it was
>  		 * handled.
>  		 */
> +		pd_trace("SET_SNK_NEGOTIATE", 0);
>  		tcpm_set_state(dev, SNK_NEGOTIATE_CAPABILITIES, 0);
>  		break;
>  	case PD_DATA_REQUEST:
> @@ -736,6 +743,7 @@ static void tcpm_pd_ctrl_request(struct udevice *dev,
>  	case PD_CTRL_GOTO_MIN:
>  		break;
>  	case PD_CTRL_PS_RDY:
> +		pd_trace("RX_PS_RDY", port->state);
>  		switch (port->state) {
>  		case SNK_TRANSITION_SINK:
>  			if (port->vbus_present) {
> @@ -775,6 +783,7 @@ static void tcpm_pd_ctrl_request(struct udevice *dev,
>  		}
>  		break;
>  	case PD_CTRL_ACCEPT:
> +		pd_trace("RX_ACCEPT", port->state);
>  		switch (port->state) {
>  		case SNK_NEGOTIATE_CAPABILITIES:
>  			tcpm_set_state(dev, SNK_TRANSITION_SINK, 0);
> @@ -1655,9 +1664,13 @@ static void run_state_machine(struct udevice *dev)
>  		}
>  		break;
>  	case SNK_NEGOTIATE_CAPABILITIES:
> +		pd_trace("SNK_NEGOTIATE_ENTER", 0);
>  		port->pd_capable = true;
>  		port->hard_reset_count = 0;
>  		ret = tcpm_pd_send_request(dev);
> +		pd_trace("SNK_NEGOTIATE_SENT", ret);
> +		pd_trace("REQ_MV", port->req_supply_voltage);
> +		pd_trace("REQ_MA", port->req_current_limit);
>  		if (ret < 0) {
>  			/* Let the Source send capabilities again. */
>  			tcpm_set_state(dev, SNK_WAIT_CAPABILITIES, 0);
> @@ -1672,8 +1685,10 @@ static void run_state_machine(struct udevice *dev)
>  			       PD_T_PS_TRANSITION);
>  		break;
>  	case SNK_READY:
> +		pd_trace("SNK_READY", 0);
>  		port->update_sink_caps = false;
>  		tcpm_typec_connect(port);
> +
>  		/*
>  		 * Here poll_event_cnt is cleared, waiting for self-powered Type-C devices
>  		 * to send DR_swap Messge until 1s (TCPM_POLL_EVENT_TIME_OUT * 500us)timeout
> @@ -2255,11 +2270,13 @@ static void tcpm_poll_event(struct udevice *dev)
>  	if (port->state == SNK_READY || port->state == SRC_READY) {
>  		int settle;
>  
> +		pd_trace("POST_READY_POLL_START", port->state);
>  		for (settle = 0; settle < 1000; settle++) {
>  			drvops->poll_event(dev);
>  			udelay(500);
>  			tcpm_check_and_run_delayed_work(dev);
>  		}
> +		pd_trace("POST_READY_POLL_DONE", port->state);
>  	}
>  
>  	if (port->state != SNK_READY && port->state != SRC_READY)
> 
> -- 
> 2.51.0
>
signature.asc (application/pgp-signature, 833 B)
-----BEGIN PGP SIGNATURE-----

iQIzBAABCgAdFiEE72YNB0Y/i3JqeVQT2O7X88g7+poFAmp3oz8ACgkQ2O7X88g7
+poi8BAAnJh6td6IA/MfStNTfnRl7u/o0W9pn5XymWwhnbS96g8//0/oLlC8JO/Q
Rf4LQIwazbGuer2oDev6lOTRlloF7HsCMolldmrVN9RJhCFDeX7e6edi8IaUklWS
/3fkA4fL+bwKQn2wssJR1b9KT4pQ8yRwAqctzvV+WOP9cnD17Y9Y+0sV6SJTm+Ta
9rPrsarS1goBKm3E7gt5BZXzzXNctqK3vEgpRNu7mfk2wnj8AZgk0FMoAgXfNgYR
CrIfxz2/I3hZ37+TDu/Arx49aUh1sc45d2oc+VdUMf5x9OlO8muZ5XMC0JizwcGX
oVhDXq2uMGnI9r1u0Vr3dmRuNfTX7X/3WVF1H7C5R4HsyhxCp6c+UpX7DjM2+ofe
UegohoIDEnR/JcTYUEN/KclbU3ju1zxarv8jMsTVsuPmH76jc8VWQCXInv2kxwQS
8FYwSKHbYDPp+LbArMGsF1YRw27l6wQPYPw2Y2HAqstMbAlQ9D1wG6LrZL0w84zP
HChvGsQoS5bog6ubjB9CPdA82nvYKzzS9X8n6MitdZej4TNYgmCoZZKDgZw9denz
cbcIjuoHHx9o2740ur/fhaMB1MrtHyMVexbyMe/ADPPbclMaWXvew5k2YUNnIqOe
OXB/RTAGjnX2B1Re4Kwpf+hcCk+SlIG4iSBZvgqOPQ9c2qpC4vQ=
=4VEM
-----END PGP SIGNATURE-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.