···221221 help
222222 Register dump
223223224224+config CMD_TCPM
225225+ bool "tcpm"
226226+ depends on TYPEC_TCPM
227227+ help
228228+ Show voltage and current negotiated via USB PD as well as the
229229+ current state of the Type C Port Manager (TCPM) state machine.
230230+224231config CMD_TLV_EEPROM
225232 bool "tlv_eeprom"
226233 depends on I2C_EEPROM
···2424CONFIG_SPL_FIT_SIGNATURE=y
2525CONFIG_SPL_LOAD_FIT=y
2626CONFIG_LEGACY_IMAGE_FORMAT=y
2727+CONFIG_OF_BOARD_SETUP=y
2728CONFIG_DEFAULT_FDT_FILE="rockchip/rk3588-rock-5b.dtb"
2829# CONFIG_DISPLAY_CPUINFO is not set
2930CONFIG_DISPLAY_BOARDINFO_LATE=y
···103104CONFIG_USB_GADGET_DOWNLOAD=y
104105CONFIG_USB_FUNCTION_ROCKUSB=y
105106CONFIG_ERRNO_STR=y
107107+CONFIG_TYPEC_TCPM=y
108108+CONFIG_TYPEC_FUSB302=y
109109+CONFIG_CMD_TCPM=y
+66
doc/usage/cmd/tcpm.rst
···11+.. SPDX-License-Identifier: GPL-2.0+:
22+33+.. index::
44+ single: tcpm (command)
55+66+tcpm command
77+============
88+99+Synopsis
1010+--------
1111+1212+::
1313+1414+ tcpm dev [devnum]
1515+ tcpm info
1616+ tcpm list
1717+1818+Description
1919+-----------
2020+2121+The tcpm command is used to control USB-PD controllers, also known as TypeC Port Manager (TCPM).
2222+2323+The 'tcpm dev' command shows or set current TCPM device.
2424+2525+ devnum
2626+ device number to change
2727+2828+The 'tcpm info' command displays the current state of the device
2929+3030+The 'tcpm list' command displays the list available devices.
3131+3232+Examples
3333+--------
3434+3535+The 'tcpm info' command displays device's status:
3636+::
3737+3838+ => tcpm info
3939+ Orientation: normal
4040+ PD Revision: rev3
4141+ Power Role: sink
4242+ Data Role: device
4343+ Voltage: 20.000 V
4444+ Current: 2.250 A
4545+4646+The current device can be shown or set via 'tcpm dev' command:
4747+::
4848+4949+ => tcpm dev
5050+ TCPM device is not set!
5151+ => tcpm dev 0
5252+ dev: 0 @ usb-typec@22
5353+ => tcpm dev
5454+ dev: 0 @ usb-typec@22
5555+5656+The list of available devices can be shown via 'tcpm list' command:
5757+::
5858+5959+ => tcpm list
6060+ | ID | Name | Parent name | Parent uclass @ seq
6161+ | 0 | usb-typec@22 | i2c@feac0000 | i2c @ 4 | status: 0
6262+6363+Configuration
6464+-------------
6565+6666+The tcpm command is only available if CONFIG_CMD_TCPM=y.
···11+# SPDX-License-Identifier: GPL-2.0
22+33+config TYPEC_TCPM
44+ tristate "USB Type-C Port Controller Manager"
55+ depends on DM
66+ help
77+ The Type-C Port Controller Manager provides a USB PD and USB Type-C
88+ state machine for use with Type-C Port Controllers.
99+1010+config TYPEC_FUSB302
1111+ tristate "Fairchild FUSB302 Type-C chip driver"
1212+ depends on DM && DM_I2C && TYPEC_TCPM
1313+ help
1414+ The Fairchild FUSB302 Type-C chip driver that works with
1515+ Type-C Port Controller Manager to provide USB PD and USB
1616+ Type-C functionalities.
···11+/* SPDX-License-Identifier: GPL-2.0-or-later */
22+/*
33+ * Copyright 2015-2017 Google, Inc
44+ * Copyright 2024 Collabora
55+ */
66+77+#ifndef __LINUX_USB_TCPM_INTERNAL_H
88+#define __LINUX_USB_TCPM_INTERNAL_H
99+1010+#define FOREACH_TCPM_STATE(S) \
1111+ S(INVALID_STATE), \
1212+ S(TOGGLING), \
1313+ S(SRC_UNATTACHED), \
1414+ S(SRC_ATTACH_WAIT), \
1515+ S(SRC_ATTACHED), \
1616+ S(SRC_STARTUP), \
1717+ S(SRC_SEND_CAPABILITIES), \
1818+ S(SRC_SEND_CAPABILITIES_TIMEOUT), \
1919+ S(SRC_NEGOTIATE_CAPABILITIES), \
2020+ S(SRC_TRANSITION_SUPPLY), \
2121+ S(SRC_READY), \
2222+ S(SRC_WAIT_NEW_CAPABILITIES), \
2323+ \
2424+ S(SNK_UNATTACHED), \
2525+ S(SNK_ATTACH_WAIT), \
2626+ S(SNK_DEBOUNCED), \
2727+ S(SNK_ATTACHED), \
2828+ S(SNK_STARTUP), \
2929+ S(SNK_DISCOVERY), \
3030+ S(SNK_DISCOVERY_DEBOUNCE), \
3131+ S(SNK_DISCOVERY_DEBOUNCE_DONE), \
3232+ S(SNK_WAIT_CAPABILITIES), \
3333+ S(SNK_NEGOTIATE_CAPABILITIES), \
3434+ S(SNK_TRANSITION_SINK), \
3535+ S(SNK_TRANSITION_SINK_VBUS), \
3636+ S(SNK_READY), \
3737+ \
3838+ S(HARD_RESET_SEND), \
3939+ S(HARD_RESET_START), \
4040+ S(SRC_HARD_RESET_VBUS_OFF), \
4141+ S(SRC_HARD_RESET_VBUS_ON), \
4242+ S(SNK_HARD_RESET_SINK_OFF), \
4343+ S(SNK_HARD_RESET_WAIT_VBUS), \
4444+ S(SNK_HARD_RESET_SINK_ON), \
4545+ \
4646+ S(SOFT_RESET), \
4747+ S(SOFT_RESET_SEND), \
4848+ \
4949+ S(DR_SWAP_ACCEPT), \
5050+ S(DR_SWAP_CHANGE_DR), \
5151+ \
5252+ S(ERROR_RECOVERY), \
5353+ S(PORT_RESET), \
5454+ S(PORT_RESET_WAIT_OFF)
5555+5656+#define GENERATE_TCPM_ENUM(e) e
5757+#define GENERATE_TCPM_STRING(s) #s
5858+#define TCPM_POLL_EVENT_TIME_OUT 2000
5959+6060+enum tcpm_state {
6161+ FOREACH_TCPM_STATE(GENERATE_TCPM_ENUM)
6262+};
6363+6464+enum pd_msg_request {
6565+ PD_MSG_NONE = 0,
6666+ PD_MSG_CTRL_REJECT,
6767+ PD_MSG_CTRL_WAIT,
6868+ PD_MSG_CTRL_NOT_SUPP,
6969+ PD_MSG_DATA_SINK_CAP,
7070+ PD_MSG_DATA_SOURCE_CAP,
7171+};
7272+7373+struct tcpm_port {
7474+ enum typec_port_type typec_type;
7575+ int typec_prefer_role;
7676+7777+ enum typec_role vconn_role;
7878+ enum typec_role pwr_role;
7979+ enum typec_data_role data_role;
8080+8181+ struct typec_partner *partner;
8282+8383+ enum typec_cc_status cc_req;
8484+ enum typec_cc_status cc1;
8585+ enum typec_cc_status cc2;
8686+ enum typec_cc_polarity polarity;
8787+8888+ bool attached;
8989+ bool connected;
9090+ int poll_event_cnt;
9191+ enum typec_port_type port_type;
9292+9393+ /*
9494+ * Set to true when vbus is greater than VSAFE5V min.
9595+ * Set to false when vbus falls below vSinkDisconnect max threshold.
9696+ */
9797+ bool vbus_present;
9898+9999+ /*
100100+ * Set to true when vbus is less than VSAFE0V max.
101101+ * Set to false when vbus is greater than VSAFE0V max.
102102+ */
103103+ bool vbus_vsafe0v;
104104+105105+ bool vbus_never_low;
106106+ bool vbus_source;
107107+ bool vbus_charge;
108108+109109+ int try_role;
110110+111111+ enum pd_msg_request queued_message;
112112+113113+ enum tcpm_state enter_state;
114114+ enum tcpm_state prev_state;
115115+ enum tcpm_state state;
116116+ enum tcpm_state delayed_state;
117117+ unsigned long delay_ms;
118118+119119+ bool state_machine_running;
120120+121121+ bool tx_complete;
122122+ enum tcpm_transmit_status tx_status;
123123+124124+ unsigned int negotiated_rev;
125125+ unsigned int message_id;
126126+ unsigned int caps_count;
127127+ unsigned int hard_reset_count;
128128+ bool pd_capable;
129129+ bool explicit_contract;
130130+ unsigned int rx_msgid;
131131+132132+ /* Partner capabilities/requests */
133133+ u32 sink_request;
134134+ u32 source_caps[PDO_MAX_OBJECTS];
135135+ unsigned int nr_source_caps;
136136+ u32 sink_caps[PDO_MAX_OBJECTS];
137137+ unsigned int nr_sink_caps;
138138+139139+ /*
140140+ * whether to wait for the Type-C device to send the DR_SWAP Message flag
141141+ * For Type-C device with Dual-Role Power and Dual-Role Data, the port side
142142+ * is used as sink + ufp, then the tcpm framework needs to wait for Type-C
143143+ * device to initiate DR_swap Message.
144144+ */
145145+ bool wait_dr_swap_message;
146146+147147+ /* Local capabilities */
148148+ u32 src_pdo[PDO_MAX_OBJECTS];
149149+ unsigned int nr_src_pdo;
150150+ u32 snk_pdo[PDO_MAX_OBJECTS];
151151+ unsigned int nr_snk_pdo;
152152+153153+ unsigned int operating_snk_mw;
154154+ bool update_sink_caps;
155155+156156+ /* Requested current / voltage to the port partner */
157157+ u32 req_current_limit;
158158+ u32 req_supply_voltage;
159159+ /* Actual current / voltage limit of the local port */
160160+ u32 current_limit;
161161+ u32 supply_voltage;
162162+163163+ /* port belongs to a self powered device */
164164+ bool self_powered;
165165+166166+ unsigned long delay_target;
167167+};
168168+169169+extern const char * const tcpm_states[];
170170+171171+int tcpm_post_probe(struct udevice *dev);
172172+173173+#endif
+149
drivers/usb/tcpm/tcpm-uclass.c
···11+// SPDX-License-Identifier: GPL-2.0+
22+/*
33+ * Copyright 2024 Collabora Ltd.
44+ *
55+ * USB Power Delivery protocol stack.
66+ */
77+88+#include <dm/device.h>
99+#include <dm/device_compat.h>
1010+#include <dm/uclass.h>
1111+#include <linux/err.h>
1212+#include <usb/tcpm.h>
1313+#include "tcpm-internal.h"
1414+1515+int tcpm_get_voltage(struct udevice *dev)
1616+{
1717+ struct tcpm_port *port = dev_get_uclass_plat(dev);
1818+1919+ return port->supply_voltage;
2020+}
2121+2222+int tcpm_get_current(struct udevice *dev)
2323+{
2424+ struct tcpm_port *port = dev_get_uclass_plat(dev);
2525+2626+ return port->current_limit;
2727+}
2828+2929+enum typec_orientation tcpm_get_orientation(struct udevice *dev)
3030+{
3131+ struct tcpm_port *port = dev_get_uclass_plat(dev);
3232+3333+ switch (port->polarity) {
3434+ case TYPEC_POLARITY_CC1:
3535+ return TYPEC_ORIENTATION_NORMAL;
3636+ case TYPEC_POLARITY_CC2:
3737+ return TYPEC_ORIENTATION_REVERSE;
3838+ default:
3939+ return TYPEC_ORIENTATION_NONE;
4040+ }
4141+}
4242+4343+const char *tcpm_get_state(struct udevice *dev)
4444+{
4545+ struct tcpm_port *port = dev_get_uclass_plat(dev);
4646+4747+ return tcpm_states[port->state];
4848+}
4949+5050+int tcpm_get_pd_rev(struct udevice *dev)
5151+{
5252+ struct tcpm_port *port = dev_get_uclass_plat(dev);
5353+5454+ return port->negotiated_rev;
5555+}
5656+5757+enum typec_role tcpm_get_pwr_role(struct udevice *dev)
5858+{
5959+ struct tcpm_port *port = dev_get_uclass_plat(dev);
6060+6161+ return port->pwr_role;
6262+}
6363+6464+enum typec_data_role tcpm_get_data_role(struct udevice *dev)
6565+{
6666+ struct tcpm_port *port = dev_get_uclass_plat(dev);
6767+6868+ return port->data_role;
6969+}
7070+7171+bool tcpm_is_connected(struct udevice *dev)
7272+{
7373+ struct tcpm_port *port = dev_get_uclass_plat(dev);
7474+7575+ return port->connected;
7676+}
7777+7878+int tcpm_get(int index, struct udevice **devp)
7979+{
8080+ return uclass_get_device(UCLASS_TCPM, index, devp);
8181+}
8282+8383+static int tcpm_post_bind(struct udevice *dev)
8484+{
8585+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
8686+ const char *cap_str;
8787+ ofnode node;
8888+ int ret;
8989+9090+ /*
9191+ * USB Power Delivery (USB PD) specification requires, that communication
9292+ * with a sink happens within roughly 5 seconds. Otherwise the source
9393+ * might assume that the sink does not support USB PD. Starting to do
9494+ * USB PD communication after that results in a hard reset, which briefly
9595+ * removes any power from the USB-C port.
9696+ *
9797+ * On systems with alternative power supplies this is not an issue, but
9898+ * systems, which get soleley powered through their USB-C port will end
9999+ * up losing their power supply and doing a board level reset. The hard
100100+ * reset will also restart the 5 second timeout. That means a operating
101101+ * system initializing USB PD will put the system into a boot loop when
102102+ * it takes more than 5 seconds from cold boot to the operating system
103103+ * starting to transmit USB PD messages.
104104+ *
105105+ * The issue can be avoided by doing the initial USB PD communication
106106+ * in U-Boot. The operating system can then re-negotiate by doing a
107107+ * soft reset, which does not trigger removal of the supply voltage.
108108+ *
109109+ * Since the TCPM state machine is quite complex and depending on the
110110+ * remote side can take quite some time to finish, this tries to limit
111111+ * the automatic probing to systems probably relying on power being
112112+ * provided by the USB-C port(s):
113113+ *
114114+ * 1. self-powered devices won't reset when the USB-C port looses power
115115+ * 2. if the power is allowed to go into anything else than sink mode
116116+ * it is not the only power source
117117+ */
118118+ ret = drvops->get_connector_node(dev, &node);
119119+ if (ret)
120120+ return ret;
121121+122122+ if (ofnode_read_bool(node, "self-powered"))
123123+ return 0;
124124+125125+ cap_str = ofnode_read_string(node, "power-role");
126126+ if (!cap_str)
127127+ return -EINVAL;
128128+129129+ if (strcmp("sink", cap_str))
130130+ return 0;
131131+132132+ /* Do not auto-probe PD controller when PD is disabled */
133133+ if (ofnode_read_bool(node, "pd-disable"))
134134+ return 0;
135135+136136+ dev_info(dev, "probing Type-C port manager...");
137137+138138+ dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
139139+140140+ return 0;
141141+}
142142+143143+UCLASS_DRIVER(tcpm) = {
144144+ .id = UCLASS_TCPM,
145145+ .name = "tcpm",
146146+ .per_device_plat_auto = sizeof(struct tcpm_port),
147147+ .post_bind = tcpm_post_bind,
148148+ .post_probe = tcpm_post_probe,
149149+};
+2288
drivers/usb/tcpm/tcpm.c
···11+// SPDX-License-Identifier: GPL-2.0+
22+/*
33+ * Copyright 2015-2017 Google, Inc
44+ *
55+ * USB Power Delivery protocol stack.
66+ */
77+88+#include <asm/gpio.h>
99+#include <asm/io.h>
1010+#include <dm.h>
1111+#include <dm/device_compat.h>
1212+#include <dm/device-internal.h>
1313+#include <dm/devres.h>
1414+#include <linux/compat.h>
1515+#include <linux/delay.h>
1616+#include <linux/err.h>
1717+#include <linux/iopoll.h>
1818+#include <time.h>
1919+#include <usb/tcpm.h>
2020+#include "tcpm-internal.h"
2121+2222+DECLARE_GLOBAL_DATA_PTR;
2323+2424+const char * const tcpm_states[] = {
2525+ FOREACH_TCPM_STATE(GENERATE_TCPM_STRING)
2626+};
2727+2828+const char * const typec_pd_rev_name[] = {
2929+ [PD_REV10] = "rev1",
3030+ [PD_REV20] = "rev2",
3131+ [PD_REV30] = "rev3",
3232+};
3333+3434+const char * const typec_role_name[] = {
3535+ [TYPEC_SINK] = "sink",
3636+ [TYPEC_SOURCE] = "source",
3737+};
3838+3939+const char * const typec_data_role_name[] = {
4040+ [TYPEC_DEVICE] = "device",
4141+ [TYPEC_HOST] = "host",
4242+};
4343+4444+const char * const typec_orientation_name[] = {
4545+ [TYPEC_ORIENTATION_NONE] = "none",
4646+ [TYPEC_ORIENTATION_NORMAL] = "normal",
4747+ [TYPEC_ORIENTATION_REVERSE] = "reverse",
4848+};
4949+5050+const char * const typec_cc_status_name[] = {
5151+ [TYPEC_CC_OPEN] = "open",
5252+ [TYPEC_CC_RA] = "ra",
5353+ [TYPEC_CC_RD] = "rd",
5454+ [TYPEC_CC_RP_DEF] = "rp-def",
5555+ [TYPEC_CC_RP_1_5] = "rp-1.5",
5656+ [TYPEC_CC_RP_3_0] = "rp-3.0",
5757+};
5858+5959+static inline bool tcpm_cc_is_sink(enum typec_cc_status cc)
6060+{
6161+ return cc == TYPEC_CC_RP_DEF ||
6262+ cc == TYPEC_CC_RP_1_5 ||
6363+ cc == TYPEC_CC_RP_3_0;
6464+}
6565+6666+static inline bool tcpm_port_is_sink(struct tcpm_port *port)
6767+{
6868+ bool cc1_is_snk = tcpm_cc_is_sink(port->cc1);
6969+ bool cc2_is_snk = tcpm_cc_is_sink(port->cc2);
7070+7171+ return (cc1_is_snk && !cc2_is_snk) ||
7272+ (cc2_is_snk && !cc1_is_snk);
7373+}
7474+7575+static inline bool tcpm_cc_is_source(enum typec_cc_status cc)
7676+{
7777+ return cc == TYPEC_CC_RD;
7878+}
7979+8080+static inline bool tcpm_port_is_source(struct tcpm_port *port)
8181+{
8282+ bool cc1_is_src = tcpm_cc_is_source(port->cc1);
8383+ bool cc2_is_src = tcpm_cc_is_source(port->cc2);
8484+8585+ return (cc1_is_src && !cc2_is_src) ||
8686+ (cc2_is_src && !cc1_is_src);
8787+}
8888+8989+static inline bool tcpm_try_src(struct tcpm_port *port)
9090+{
9191+ return port->try_role == TYPEC_SOURCE &&
9292+ port->port_type == TYPEC_PORT_DRP;
9393+}
9494+9595+static inline void tcpm_reset_event_cnt(struct udevice *dev)
9696+{
9797+ struct tcpm_port *port = dev_get_uclass_plat(dev);
9898+9999+ port->poll_event_cnt = 0;
100100+}
101101+102102+static enum tcpm_state tcpm_default_state(struct tcpm_port *port)
103103+{
104104+ if (port->port_type == TYPEC_PORT_DRP) {
105105+ if (port->try_role == TYPEC_SINK)
106106+ return SNK_UNATTACHED;
107107+ else if (port->try_role == TYPEC_SOURCE)
108108+ return SRC_UNATTACHED;
109109+ } else if (port->port_type == TYPEC_PORT_SNK) {
110110+ return SNK_UNATTACHED;
111111+ }
112112+ return SRC_UNATTACHED;
113113+}
114114+115115+static bool tcpm_port_is_disconnected(struct tcpm_port *port)
116116+{
117117+ return (!port->attached && port->cc1 == TYPEC_CC_OPEN &&
118118+ port->cc2 == TYPEC_CC_OPEN) ||
119119+ (port->attached && ((port->polarity == TYPEC_POLARITY_CC1 &&
120120+ port->cc1 == TYPEC_CC_OPEN) ||
121121+ (port->polarity == TYPEC_POLARITY_CC2 &&
122122+ port->cc2 == TYPEC_CC_OPEN)));
123123+}
124124+125125+static void tcpm_set_cc(struct udevice *dev, enum typec_cc_status cc)
126126+{
127127+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
128128+ struct tcpm_port *port = dev_get_uclass_plat(dev);
129129+130130+ dev_dbg(dev, "TCPM: set cc = %d\n", cc);
131131+ port->cc_req = cc;
132132+ drvops->set_cc(dev, cc);
133133+}
134134+135135+/*
136136+ * Determine RP value to set based on maximum current supported
137137+ * by a port if configured as source.
138138+ * Returns CC value to report to link partner.
139139+ */
140140+static enum typec_cc_status tcpm_rp_cc(struct tcpm_port *port)
141141+{
142142+ const u32 *src_pdo = port->src_pdo;
143143+ int nr_pdo = port->nr_src_pdo;
144144+ int i;
145145+146146+ /*
147147+ * Search for first entry with matching voltage.
148148+ * It should report the maximum supported current.
149149+ */
150150+ for (i = 0; i < nr_pdo; i++) {
151151+ const u32 pdo = src_pdo[i];
152152+153153+ if (pdo_type(pdo) == PDO_TYPE_FIXED &&
154154+ pdo_fixed_voltage(pdo) == 5000) {
155155+ unsigned int curr = pdo_max_current(pdo);
156156+157157+ if (curr >= 3000)
158158+ return TYPEC_CC_RP_3_0;
159159+ else if (curr >= 1500)
160160+ return TYPEC_CC_RP_1_5;
161161+ return TYPEC_CC_RP_DEF;
162162+ }
163163+ }
164164+165165+ return TYPEC_CC_RP_DEF;
166166+}
167167+168168+static void tcpm_check_and_run_delayed_work(struct udevice *dev);
169169+170170+static bool tcpm_transmit_helper(struct udevice *dev)
171171+{
172172+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
173173+ struct tcpm_port *port = dev_get_uclass_plat(dev);
174174+175175+ drvops->poll_event(dev);
176176+ udelay(500);
177177+ tcpm_check_and_run_delayed_work(dev);
178178+ return port->tx_complete;
179179+}
180180+181181+static int tcpm_pd_transmit(struct udevice *dev,
182182+ enum tcpm_transmit_type type,
183183+ const struct pd_message *msg)
184184+{
185185+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
186186+ struct tcpm_port *port = dev_get_uclass_plat(dev);
187187+ u32 timeout_us = PD_T_TCPC_TX_TIMEOUT * 1000;
188188+ bool tx_complete;
189189+ int ret;
190190+191191+ if (msg)
192192+ dev_dbg(dev, "TCPM: PD TX, header: %#x\n",
193193+ le16_to_cpu(msg->header));
194194+ else
195195+ dev_dbg(dev, "TCPM: PD TX, type: %#x\n", type);
196196+197197+ port->tx_complete = false;
198198+ ret = drvops->pd_transmit(dev, type, msg, port->negotiated_rev);
199199+ if (ret < 0)
200200+ return ret;
201201+202202+ /*
203203+ * At this point we basically need to block until the TCPM controller
204204+ * returns successful transmission. Since this is usually done using
205205+ * the generic interrupt status bits, we poll for any events. That
206206+ * will clear the interrupt status, so we also need to process any
207207+ * of the incoming events. This means we will do more processing and
208208+ * thus let's give everything a bit more time.
209209+ */
210210+ timeout_us *= 5;
211211+ ret = read_poll_timeout(tcpm_transmit_helper, tx_complete,
212212+ !tx_complete, false, timeout_us, dev);
213213+ if (ret < 0) {
214214+ dev_err(dev, "TCPM: PD transmit data failed: %d\n", ret);
215215+ return ret;
216216+ }
217217+218218+ switch (port->tx_status) {
219219+ case TCPC_TX_SUCCESS:
220220+ port->message_id = (port->message_id + 1) & PD_HEADER_ID_MASK;
221221+ break;
222222+ case TCPC_TX_DISCARDED:
223223+ ret = -EAGAIN;
224224+ break;
225225+ case TCPC_TX_FAILED:
226226+ default:
227227+ ret = -EIO;
228228+ break;
229229+ }
230230+231231+ return ret;
232232+}
233233+234234+void tcpm_pd_transmit_complete(struct udevice *dev,
235235+ enum tcpm_transmit_status status)
236236+{
237237+ struct tcpm_port *port = dev_get_uclass_plat(dev);
238238+239239+ dev_dbg(dev, "TCPM: PD TX complete, status: %u\n", status);
240240+ tcpm_reset_event_cnt(dev);
241241+ port->tx_status = status;
242242+ port->tx_complete = true;
243243+}
244244+245245+static int tcpm_set_polarity(struct udevice *dev,
246246+ enum typec_cc_polarity polarity)
247247+{
248248+ struct tcpm_port *port = dev_get_uclass_plat(dev);
249249+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
250250+ int ret;
251251+252252+ dev_dbg(dev, "TCPM: set polarity = %d\n", polarity);
253253+254254+ if (drvops->set_polarity) {
255255+ ret = drvops->set_polarity(dev, polarity);
256256+ if (ret < 0)
257257+ return ret;
258258+ }
259259+260260+ port->polarity = polarity;
261261+262262+ return 0;
263263+}
264264+265265+static int tcpm_set_vconn(struct udevice *dev, bool enable)
266266+{
267267+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
268268+ struct tcpm_port *port = dev_get_uclass_plat(dev);
269269+ int ret;
270270+271271+ dev_dbg(dev, "TCPM: set vconn = %d\n", enable);
272272+273273+ ret = drvops->set_vconn(dev, enable);
274274+ if (!ret)
275275+ port->vconn_role = enable ? TYPEC_SOURCE : TYPEC_SINK;
276276+277277+ return ret;
278278+}
279279+280280+static inline u32 tcpm_get_current_limit(struct tcpm_port *port)
281281+{
282282+ switch (port->polarity ? port->cc2 : port->cc1) {
283283+ case TYPEC_CC_RP_1_5:
284284+ return 1500;
285285+ case TYPEC_CC_RP_3_0:
286286+ return 3000;
287287+ case TYPEC_CC_RP_DEF:
288288+ default:
289289+ return 0;
290290+ }
291291+}
292292+293293+static int tcpm_set_current_limit(struct udevice *dev, u32 max_ma, u32 mv)
294294+{
295295+ struct tcpm_port *port = dev_get_uclass_plat(dev);
296296+ int ret = -EOPNOTSUPP;
297297+298298+ dev_info(dev, "TCPM: set voltage limit = %u mV\n", mv);
299299+ dev_info(dev, "TCPM: set current limit = %u mA\n", max_ma);
300300+301301+ port->supply_voltage = mv;
302302+ port->current_limit = max_ma;
303303+304304+ return ret;
305305+}
306306+307307+static int tcpm_set_attached_state(struct udevice *dev, bool attached)
308308+{
309309+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
310310+ struct tcpm_port *port = dev_get_uclass_plat(dev);
311311+312312+ return drvops->set_roles(dev, attached, port->pwr_role,
313313+ port->data_role);
314314+}
315315+316316+static int tcpm_set_roles(struct udevice *dev, bool attached,
317317+ enum typec_role role, enum typec_data_role data)
318318+{
319319+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
320320+ struct tcpm_port *port = dev_get_uclass_plat(dev);
321321+ int ret;
322322+323323+ ret = drvops->set_roles(dev, attached, role, data);
324324+ if (ret < 0)
325325+ return ret;
326326+327327+ port->pwr_role = role;
328328+ port->data_role = data;
329329+330330+ return 0;
331331+}
332332+333333+static int tcpm_pd_send_source_caps(struct udevice *dev)
334334+{
335335+ struct tcpm_port *port = dev_get_uclass_plat(dev);
336336+ struct pd_message msg;
337337+ int i;
338338+339339+ memset(&msg, 0, sizeof(msg));
340340+341341+ if (!port->nr_src_pdo) {
342342+ /* No source capabilities defined, sink only */
343343+ msg.header = PD_HEADER_LE(PD_CTRL_REJECT,
344344+ port->pwr_role,
345345+ port->data_role,
346346+ port->negotiated_rev,
347347+ port->message_id, 0);
348348+ } else {
349349+ msg.header = PD_HEADER_LE(PD_DATA_SOURCE_CAP,
350350+ port->pwr_role,
351351+ port->data_role,
352352+ port->negotiated_rev,
353353+ port->message_id,
354354+ port->nr_src_pdo);
355355+ }
356356+357357+ for (i = 0; i < port->nr_src_pdo; i++)
358358+ msg.payload[i] = cpu_to_le32(port->src_pdo[i]);
359359+360360+ return tcpm_pd_transmit(dev, TCPC_TX_SOP, &msg);
361361+}
362362+363363+static int tcpm_pd_send_sink_caps(struct udevice *dev)
364364+{
365365+ struct tcpm_port *port = dev_get_uclass_plat(dev);
366366+ struct pd_message msg;
367367+ unsigned int i;
368368+369369+ memset(&msg, 0, sizeof(msg));
370370+371371+ if (!port->nr_snk_pdo) {
372372+ /* No sink capabilities defined, source only */
373373+ msg.header = PD_HEADER_LE(PD_CTRL_REJECT,
374374+ port->pwr_role,
375375+ port->data_role,
376376+ port->negotiated_rev,
377377+ port->message_id, 0);
378378+ } else {
379379+ msg.header = PD_HEADER_LE(PD_DATA_SINK_CAP,
380380+ port->pwr_role,
381381+ port->data_role,
382382+ port->negotiated_rev,
383383+ port->message_id,
384384+ port->nr_snk_pdo);
385385+ }
386386+387387+ for (i = 0; i < port->nr_snk_pdo; i++)
388388+ msg.payload[i] = cpu_to_le32(port->snk_pdo[i]);
389389+390390+ return tcpm_pd_transmit(dev, TCPC_TX_SOP, &msg);
391391+}
392392+393393+static void tcpm_state_machine(struct udevice *dev);
394394+395395+static inline void tcpm_timer_uninit(struct udevice *dev)
396396+{
397397+ struct tcpm_port *port = dev_get_uclass_plat(dev);
398398+399399+ port->delay_target = 0;
400400+}
401401+402402+static void tcpm_timer_init(struct udevice *dev, uint32_t ms)
403403+{
404404+ struct tcpm_port *port = dev_get_uclass_plat(dev);
405405+ unsigned long time_us = ms * 1000;
406406+407407+ port->delay_target = timer_get_us() + time_us;
408408+}
409409+410410+static void tcpm_check_and_run_delayed_work(struct udevice *dev)
411411+{
412412+ struct tcpm_port *port = dev_get_uclass_plat(dev);
413413+414414+ /* no delayed state changes scheduled */
415415+ if (port->delay_target == 0)
416416+ return;
417417+418418+ /* it's not yet time */
419419+ if (timer_get_us() < port->delay_target)
420420+ return;
421421+422422+ tcpm_timer_uninit(dev);
423423+ tcpm_state_machine(dev);
424424+}
425425+426426+static void mod_tcpm_delayed_work(struct udevice *dev, unsigned int delay_ms)
427427+{
428428+ if (delay_ms) {
429429+ tcpm_timer_init(dev, delay_ms);
430430+ } else {
431431+ tcpm_timer_uninit(dev);
432432+ tcpm_state_machine(dev);
433433+ }
434434+}
435435+436436+static void tcpm_set_state(struct udevice *dev, enum tcpm_state state,
437437+ unsigned int delay_ms)
438438+{
439439+ struct tcpm_port *port = dev_get_uclass_plat(dev);
440440+441441+ if (delay_ms) {
442442+ dev_dbg(dev, "TCPM: pending state change %s -> %s @ %u ms [%s]\n",
443443+ tcpm_states[port->state], tcpm_states[state], delay_ms,
444444+ typec_pd_rev_name[port->negotiated_rev]);
445445+ port->delayed_state = state;
446446+ mod_tcpm_delayed_work(dev, delay_ms);
447447+ port->delay_ms = delay_ms;
448448+ } else {
449449+ dev_dbg(dev, "TCPM: state change %s -> %s\n",
450450+ tcpm_states[port->state], tcpm_states[state]);
451451+ port->delayed_state = INVALID_STATE;
452452+ port->prev_state = port->state;
453453+ port->state = state;
454454+ /*
455455+ * Don't re-queue the state machine work item if we're currently
456456+ * in the state machine and we're immediately changing states.
457457+ * tcpm_state_machine_work() will continue running the state
458458+ * machine.
459459+ */
460460+ if (!port->state_machine_running)
461461+ mod_tcpm_delayed_work(dev, 0);
462462+ }
463463+}
464464+465465+static void tcpm_set_state_cond(struct udevice *dev, enum tcpm_state state,
466466+ unsigned int delay_ms)
467467+{
468468+ struct tcpm_port *port = dev_get_uclass_plat(dev);
469469+470470+ if (port->enter_state == port->state)
471471+ tcpm_set_state(dev, state, delay_ms);
472472+ else
473473+ dev_dbg(dev, "TCPM: skipped %sstate change %s -> %s [%u ms], context state %s [%s]\n",
474474+ delay_ms ? "delayed " : "",
475475+ tcpm_states[port->state], tcpm_states[state],
476476+ delay_ms, tcpm_states[port->enter_state],
477477+ typec_pd_rev_name[port->negotiated_rev]);
478478+}
479479+480480+static void tcpm_queue_message(struct udevice *dev,
481481+ enum pd_msg_request message)
482482+{
483483+ struct tcpm_port *port = dev_get_uclass_plat(dev);
484484+485485+ port->queued_message = message;
486486+ mod_tcpm_delayed_work(dev, 0);
487487+}
488488+489489+enum pdo_err {
490490+ PDO_NO_ERR,
491491+ PDO_ERR_NO_VSAFE5V,
492492+ PDO_ERR_VSAFE5V_NOT_FIRST,
493493+ PDO_ERR_PDO_TYPE_NOT_IN_ORDER,
494494+ PDO_ERR_FIXED_NOT_SORTED,
495495+ PDO_ERR_VARIABLE_BATT_NOT_SORTED,
496496+ PDO_ERR_DUPE_PDO,
497497+ PDO_ERR_PPS_APDO_NOT_SORTED,
498498+ PDO_ERR_DUPE_PPS_APDO,
499499+};
500500+501501+static const char * const pdo_err_msg[] = {
502502+ [PDO_ERR_NO_VSAFE5V] =
503503+ " err: source/sink caps should at least have vSafe5V",
504504+ [PDO_ERR_VSAFE5V_NOT_FIRST] =
505505+ " err: vSafe5V Fixed Supply Object Shall always be the first object",
506506+ [PDO_ERR_PDO_TYPE_NOT_IN_ORDER] =
507507+ " err: PDOs should be in the following order: Fixed; Battery; Variable",
508508+ [PDO_ERR_FIXED_NOT_SORTED] =
509509+ " err: Fixed supply pdos should be in increasing order of their fixed voltage",
510510+ [PDO_ERR_VARIABLE_BATT_NOT_SORTED] =
511511+ " err: Variable/Battery supply pdos should be in increasing order of their minimum voltage",
512512+ [PDO_ERR_DUPE_PDO] =
513513+ " err: Variable/Batt supply pdos cannot have same min/max voltage",
514514+ [PDO_ERR_PPS_APDO_NOT_SORTED] =
515515+ " err: Programmable power supply apdos should be in increasing order of their maximum voltage",
516516+ [PDO_ERR_DUPE_PPS_APDO] =
517517+ " err: Programmable power supply apdos cannot have same min/max voltage and max current",
518518+};
519519+520520+static enum pdo_err tcpm_caps_err(struct udevice *dev, const u32 *pdo,
521521+ unsigned int nr_pdo)
522522+{
523523+ unsigned int i;
524524+525525+ /* Should at least contain vSafe5v */
526526+ if (nr_pdo < 1)
527527+ return PDO_ERR_NO_VSAFE5V;
528528+529529+ /* The vSafe5V Fixed Supply Object Shall always be the first object */
530530+ if (pdo_type(pdo[0]) != PDO_TYPE_FIXED ||
531531+ pdo_fixed_voltage(pdo[0]) != VSAFE5V)
532532+ return PDO_ERR_VSAFE5V_NOT_FIRST;
533533+534534+ for (i = 1; i < nr_pdo; i++) {
535535+ if (pdo_type(pdo[i]) < pdo_type(pdo[i - 1])) {
536536+ return PDO_ERR_PDO_TYPE_NOT_IN_ORDER;
537537+ } else if (pdo_type(pdo[i]) == pdo_type(pdo[i - 1])) {
538538+ enum pd_pdo_type type = pdo_type(pdo[i]);
539539+540540+ switch (type) {
541541+ /*
542542+ * The remaining Fixed Supply Objects, if
543543+ * present, shall be sent in voltage order;
544544+ * lowest to highest.
545545+ */
546546+ case PDO_TYPE_FIXED:
547547+ if (pdo_fixed_voltage(pdo[i]) <=
548548+ pdo_fixed_voltage(pdo[i - 1]))
549549+ return PDO_ERR_FIXED_NOT_SORTED;
550550+ break;
551551+ /*
552552+ * The Battery Supply Objects and Variable
553553+ * supply, if present shall be sent in Minimum
554554+ * Voltage order; lowest to highest.
555555+ */
556556+ case PDO_TYPE_VAR:
557557+ case PDO_TYPE_BATT:
558558+ if (pdo_min_voltage(pdo[i]) <
559559+ pdo_min_voltage(pdo[i - 1]))
560560+ return PDO_ERR_VARIABLE_BATT_NOT_SORTED;
561561+ else if ((pdo_min_voltage(pdo[i]) ==
562562+ pdo_min_voltage(pdo[i - 1])) &&
563563+ (pdo_max_voltage(pdo[i]) ==
564564+ pdo_max_voltage(pdo[i - 1])))
565565+ return PDO_ERR_DUPE_PDO;
566566+ break;
567567+ /*
568568+ * The Programmable Power Supply APDOs, if present,
569569+ * shall be sent in Maximum Voltage order;
570570+ * lowest to highest.
571571+ */
572572+ case PDO_TYPE_APDO:
573573+ if (pdo_apdo_type(pdo[i]) != APDO_TYPE_PPS)
574574+ break;
575575+576576+ if (pdo_pps_apdo_max_voltage(pdo[i]) <
577577+ pdo_pps_apdo_max_voltage(pdo[i - 1]))
578578+ return PDO_ERR_PPS_APDO_NOT_SORTED;
579579+ else if (pdo_pps_apdo_min_voltage(pdo[i]) ==
580580+ pdo_pps_apdo_min_voltage(pdo[i - 1]) &&
581581+ pdo_pps_apdo_max_voltage(pdo[i]) ==
582582+ pdo_pps_apdo_max_voltage(pdo[i - 1]) &&
583583+ pdo_pps_apdo_max_current(pdo[i]) ==
584584+ pdo_pps_apdo_max_current(pdo[i - 1]))
585585+ return PDO_ERR_DUPE_PPS_APDO;
586586+ break;
587587+ default:
588588+ dev_err(dev, "TCPM: Unknown pdo type\n");
589589+ }
590590+ }
591591+ }
592592+593593+ return PDO_NO_ERR;
594594+}
595595+596596+static int tcpm_validate_caps(struct udevice *dev, const u32 *pdo,
597597+ unsigned int nr_pdo)
598598+{
599599+ enum pdo_err err_index = tcpm_caps_err(dev, pdo, nr_pdo);
600600+601601+ if (err_index != PDO_NO_ERR) {
602602+ dev_err(dev, "TCPM:%s\n", pdo_err_msg[err_index]);
603603+ return -EINVAL;
604604+ }
605605+606606+ return 0;
607607+}
608608+609609+/*
610610+ * PD (data, control) command handling functions
611611+ */
612612+static inline enum tcpm_state ready_state(struct tcpm_port *port)
613613+{
614614+ if (port->pwr_role == TYPEC_SOURCE)
615615+ return SRC_READY;
616616+ else
617617+ return SNK_READY;
618618+}
619619+620620+static void tcpm_pd_data_request(struct udevice *dev,
621621+ const struct pd_message *msg)
622622+{
623623+ enum pd_data_msg_type type = pd_header_type_le(msg->header);
624624+ struct tcpm_port *port = dev_get_uclass_plat(dev);
625625+ unsigned int cnt = pd_header_cnt_le(msg->header);
626626+ unsigned int rev = pd_header_rev_le(msg->header);
627627+ unsigned int i;
628628+629629+ switch (type) {
630630+ case PD_DATA_SOURCE_CAP:
631631+ for (i = 0; i < cnt; i++)
632632+ port->source_caps[i] = le32_to_cpu(msg->payload[i]);
633633+634634+ port->nr_source_caps = cnt;
635635+636636+ tcpm_validate_caps(dev, port->source_caps,
637637+ port->nr_source_caps);
638638+639639+ /*
640640+ * Adjust revision in subsequent message headers, as required,
641641+ * to comply with 6.2.1.1.5 of the USB PD 3.0 spec. We don't
642642+ * support Rev 1.0 so just do nothing in that scenario.
643643+ */
644644+ if (rev == PD_REV10)
645645+ break;
646646+647647+ if (rev < PD_MAX_REV)
648648+ port->negotiated_rev = rev;
649649+650650+ if ((pdo_type(port->source_caps[0]) == PDO_TYPE_FIXED) &&
651651+ (port->source_caps[0] & PDO_FIXED_DUAL_ROLE) &&
652652+ (port->source_caps[0] & PDO_FIXED_DATA_SWAP)) {
653653+ /* Dual role power and data, eg: self-powered Type-C */
654654+ port->wait_dr_swap_message = true;
655655+ } else {
656656+ /* Non-Dual role power, eg: adapter */
657657+ port->wait_dr_swap_message = false;
658658+ }
659659+660660+ /*
661661+ * This message may be received even if VBUS is not
662662+ * present. This is quite unexpected; see USB PD
663663+ * specification, sections 8.3.3.6.3.1 and 8.3.3.6.3.2.
664664+ * However, at the same time, we must be ready to
665665+ * receive this message and respond to it 15ms after
666666+ * receiving PS_RDY during power swap operations, no matter
667667+ * if VBUS is available or not (USB PD specification,
668668+ * section 6.5.9.2).
669669+ * So we need to accept the message either way,
670670+ * but be prepared to keep waiting for VBUS after it was
671671+ * handled.
672672+ */
673673+ tcpm_set_state(dev, SNK_NEGOTIATE_CAPABILITIES, 0);
674674+ break;
675675+ case PD_DATA_REQUEST:
676676+ /*
677677+ * Adjust revision in subsequent message headers, as required,
678678+ * to comply with 6.2.1.1.5 of the USB PD 3.0 spec. We don't
679679+ * support Rev 1.0 so just reject in that scenario.
680680+ */
681681+ if (rev == PD_REV10) {
682682+ tcpm_queue_message(dev, PD_MSG_CTRL_REJECT);
683683+ break;
684684+ }
685685+686686+ if (rev < PD_MAX_REV)
687687+ port->negotiated_rev = rev;
688688+689689+ port->sink_request = le32_to_cpu(msg->payload[0]);
690690+691691+ tcpm_set_state(dev, SRC_NEGOTIATE_CAPABILITIES, 0);
692692+ break;
693693+ case PD_DATA_SINK_CAP:
694694+ /* We don't do anything with this at the moment... */
695695+ for (i = 0; i < cnt; i++)
696696+ port->sink_caps[i] = le32_to_cpu(msg->payload[i]);
697697+698698+ port->nr_sink_caps = cnt;
699699+ break;
700700+ default:
701701+ break;
702702+ }
703703+}
704704+705705+static void tcpm_pd_ctrl_request(struct udevice *dev,
706706+ const struct pd_message *msg)
707707+{
708708+ enum pd_ctrl_msg_type type = pd_header_type_le(msg->header);
709709+ struct tcpm_port *port = dev_get_uclass_plat(dev);
710710+ enum tcpm_state next_state;
711711+712712+ switch (type) {
713713+ case PD_CTRL_GOOD_CRC:
714714+ case PD_CTRL_PING:
715715+ break;
716716+ case PD_CTRL_GET_SOURCE_CAP:
717717+ switch (port->state) {
718718+ case SRC_READY:
719719+ case SNK_READY:
720720+ tcpm_queue_message(dev, PD_MSG_DATA_SOURCE_CAP);
721721+ break;
722722+ default:
723723+ tcpm_queue_message(dev, PD_MSG_CTRL_REJECT);
724724+ break;
725725+ }
726726+ break;
727727+ case PD_CTRL_GET_SINK_CAP:
728728+ switch (port->state) {
729729+ case SRC_READY:
730730+ case SNK_READY:
731731+ tcpm_queue_message(dev, PD_MSG_DATA_SINK_CAP);
732732+ break;
733733+ default:
734734+ tcpm_queue_message(dev, PD_MSG_CTRL_REJECT);
735735+ break;
736736+ }
737737+ break;
738738+ case PD_CTRL_GOTO_MIN:
739739+ break;
740740+ case PD_CTRL_PS_RDY:
741741+ switch (port->state) {
742742+ case SNK_TRANSITION_SINK:
743743+ if (port->vbus_present) {
744744+ tcpm_set_current_limit(dev,
745745+ port->req_current_limit,
746746+ port->req_supply_voltage);
747747+ port->explicit_contract = true;
748748+ tcpm_set_state(dev, SNK_READY, 0);
749749+ } else {
750750+ /*
751751+ * Seen after power swap. Keep waiting for VBUS
752752+ * in a transitional state.
753753+ */
754754+ tcpm_set_state(dev,
755755+ SNK_TRANSITION_SINK_VBUS, 0);
756756+ }
757757+ break;
758758+ default:
759759+ break;
760760+ }
761761+ break;
762762+ case PD_CTRL_REJECT:
763763+ case PD_CTRL_WAIT:
764764+ case PD_CTRL_NOT_SUPP:
765765+ switch (port->state) {
766766+ case SNK_NEGOTIATE_CAPABILITIES:
767767+ /* USB PD specification, Figure 8-43 */
768768+ if (port->explicit_contract)
769769+ next_state = SNK_READY;
770770+ else
771771+ next_state = SNK_WAIT_CAPABILITIES;
772772+773773+ tcpm_set_state(dev, next_state, 0);
774774+ break;
775775+ default:
776776+ break;
777777+ }
778778+ break;
779779+ case PD_CTRL_ACCEPT:
780780+ switch (port->state) {
781781+ case SNK_NEGOTIATE_CAPABILITIES:
782782+ tcpm_set_state(dev, SNK_TRANSITION_SINK, 0);
783783+ break;
784784+ case SOFT_RESET_SEND:
785785+ port->message_id = 0;
786786+ port->rx_msgid = -1;
787787+ if (port->pwr_role == TYPEC_SOURCE)
788788+ next_state = SRC_SEND_CAPABILITIES;
789789+ else
790790+ next_state = SNK_WAIT_CAPABILITIES;
791791+ tcpm_set_state(dev, next_state, 0);
792792+ break;
793793+ default:
794794+ break;
795795+ }
796796+ break;
797797+ case PD_CTRL_SOFT_RESET:
798798+ tcpm_set_state(dev, SOFT_RESET, 0);
799799+ break;
800800+ case PD_CTRL_DR_SWAP:
801801+ if (port->port_type != TYPEC_PORT_DRP) {
802802+ tcpm_queue_message(dev, PD_MSG_CTRL_REJECT);
803803+ break;
804804+ }
805805+ /*
806806+ * 6.3.9: If an alternate mode is active, a request to swap
807807+ * alternate modes shall trigger a port reset.
808808+ */
809809+ switch (port->state) {
810810+ case SRC_READY:
811811+ case SNK_READY:
812812+ tcpm_set_state(dev, DR_SWAP_ACCEPT, 0);
813813+ break;
814814+ default:
815815+ tcpm_queue_message(dev, PD_MSG_CTRL_WAIT);
816816+ break;
817817+ }
818818+ break;
819819+ case PD_CTRL_PR_SWAP:
820820+ case PD_CTRL_VCONN_SWAP:
821821+ case PD_CTRL_GET_SOURCE_CAP_EXT:
822822+ case PD_CTRL_GET_STATUS:
823823+ case PD_CTRL_FR_SWAP:
824824+ case PD_CTRL_GET_PPS_STATUS:
825825+ case PD_CTRL_GET_COUNTRY_CODES:
826826+ /* Currently not supported */
827827+ dev_err(dev, "TCPM: Currently not supported type %#x\n", type);
828828+ tcpm_queue_message(dev, PD_MSG_CTRL_NOT_SUPP);
829829+ break;
830830+ default:
831831+ dev_err(dev, "TCPM: Unrecognized ctrl message type %#x\n", type);
832832+ break;
833833+ }
834834+}
835835+836836+static void tcpm_pd_rx_handler(struct udevice *dev,
837837+ const struct pd_message *msg)
838838+{
839839+ struct tcpm_port *port = dev_get_uclass_plat(dev);
840840+ unsigned int cnt = pd_header_cnt_le(msg->header);
841841+ bool remote_is_host, local_is_host;
842842+843843+ dev_dbg(dev, "TCPM: PD RX, header: %#x [%d]\n",
844844+ le16_to_cpu(msg->header), port->attached);
845845+846846+ if (port->attached) {
847847+ enum pd_ctrl_msg_type type = pd_header_type_le(msg->header);
848848+ unsigned int msgid = pd_header_msgid_le(msg->header);
849849+850850+ /*
851851+ * USB PD standard, 6.6.1.2:
852852+ * "... if MessageID value in a received Message is the
853853+ * same as the stored value, the receiver shall return a
854854+ * GoodCRC Message with that MessageID value and drop
855855+ * the Message (this is a retry of an already received
856856+ * Message). Note: this shall not apply to the Soft_Reset
857857+ * Message which always has a MessageID value of zero."
858858+ */
859859+ if (msgid == port->rx_msgid && type != PD_CTRL_SOFT_RESET)
860860+ return;
861861+ port->rx_msgid = msgid;
862862+863863+ /*
864864+ * If both ends believe to be DFP/host, we have a data role
865865+ * mismatch.
866866+ */
867867+ remote_is_host = !!(le16_to_cpu(msg->header) & PD_HEADER_DATA_ROLE);
868868+ local_is_host = port->data_role == TYPEC_HOST;
869869+ if (remote_is_host == local_is_host) {
870870+ dev_err(dev, "TCPM: data role mismatch, initiating error recovery\n");
871871+ tcpm_set_state(dev, ERROR_RECOVERY, 0);
872872+ } else {
873873+ if (cnt)
874874+ tcpm_pd_data_request(dev, msg);
875875+ else
876876+ tcpm_pd_ctrl_request(dev, msg);
877877+ }
878878+ }
879879+}
880880+881881+void tcpm_pd_receive(struct udevice *dev, const struct pd_message *msg)
882882+{
883883+ tcpm_reset_event_cnt(dev);
884884+ tcpm_pd_rx_handler(dev, msg);
885885+}
886886+887887+static int tcpm_pd_send_control(struct udevice *dev,
888888+ enum pd_ctrl_msg_type type)
889889+{
890890+ struct tcpm_port *port = dev_get_uclass_plat(dev);
891891+ struct pd_message msg;
892892+893893+ memset(&msg, 0, sizeof(msg));
894894+ msg.header = PD_HEADER_LE(type, port->pwr_role,
895895+ port->data_role,
896896+ port->negotiated_rev,
897897+ port->message_id, 0);
898898+899899+ return tcpm_pd_transmit(dev, TCPC_TX_SOP, &msg);
900900+}
901901+902902+/*
903903+ * Send queued message without affecting state.
904904+ * Return true if state machine should go back to sleep,
905905+ * false otherwise.
906906+ */
907907+static bool tcpm_send_queued_message(struct udevice *dev)
908908+{
909909+ struct tcpm_port *port = dev_get_uclass_plat(dev);
910910+ enum pd_msg_request queued_message;
911911+ int max_messages = 100;
912912+913913+ do {
914914+ queued_message = port->queued_message;
915915+ port->queued_message = PD_MSG_NONE;
916916+ max_messages--;
917917+918918+ switch (queued_message) {
919919+ case PD_MSG_CTRL_WAIT:
920920+ tcpm_pd_send_control(dev, PD_CTRL_WAIT);
921921+ break;
922922+ case PD_MSG_CTRL_REJECT:
923923+ tcpm_pd_send_control(dev, PD_CTRL_REJECT);
924924+ break;
925925+ case PD_MSG_CTRL_NOT_SUPP:
926926+ tcpm_pd_send_control(dev, PD_CTRL_NOT_SUPP);
927927+ break;
928928+ case PD_MSG_DATA_SINK_CAP:
929929+ tcpm_pd_send_sink_caps(dev);
930930+ break;
931931+ case PD_MSG_DATA_SOURCE_CAP:
932932+ tcpm_pd_send_source_caps(dev);
933933+ break;
934934+ default:
935935+ break;
936936+ }
937937+ } while (max_messages > 0 && port->queued_message != PD_MSG_NONE);
938938+939939+ if (!max_messages)
940940+ dev_err(dev, "Aborted sending of too many queued messages\n");
941941+942942+ return false;
943943+}
944944+945945+static int tcpm_pd_check_request(struct udevice *dev)
946946+{
947947+ struct tcpm_port *port = dev_get_uclass_plat(dev);
948948+ u32 pdo, rdo = port->sink_request;
949949+ unsigned int max, op, pdo_max, index;
950950+ enum pd_pdo_type type;
951951+952952+ index = rdo_index(rdo);
953953+ if (!index || index > port->nr_src_pdo)
954954+ return -EINVAL;
955955+956956+ pdo = port->src_pdo[index - 1];
957957+ type = pdo_type(pdo);
958958+ switch (type) {
959959+ case PDO_TYPE_FIXED:
960960+ case PDO_TYPE_VAR:
961961+ max = rdo_max_current(rdo);
962962+ op = rdo_op_current(rdo);
963963+ pdo_max = pdo_max_current(pdo);
964964+965965+ if (op > pdo_max)
966966+ return -EINVAL;
967967+ if (max > pdo_max && !(rdo & RDO_CAP_MISMATCH))
968968+ return -EINVAL;
969969+970970+ if (type == PDO_TYPE_FIXED)
971971+ dev_dbg(dev, "TCPM: Requested %u mV, %u mA for %u / %u mA\n",
972972+ pdo_fixed_voltage(pdo), pdo_max, op, max);
973973+ else
974974+ dev_dbg(dev, "TCPM: Requested %u -> %u mV, %u mA for %u / %u mA\n",
975975+ pdo_min_voltage(pdo), pdo_max_voltage(pdo),
976976+ pdo_max, op, max);
977977+ break;
978978+ case PDO_TYPE_BATT:
979979+ max = rdo_max_power(rdo);
980980+ op = rdo_op_power(rdo);
981981+ pdo_max = pdo_max_power(pdo);
982982+983983+ if (op > pdo_max)
984984+ return -EINVAL;
985985+ if (max > pdo_max && !(rdo & RDO_CAP_MISMATCH))
986986+ return -EINVAL;
987987+ dev_info(dev, "TCPM: Requested %u -> %u mV, %u mW for %u / %u mW\n",
988988+ pdo_min_voltage(pdo), pdo_max_voltage(pdo),
989989+ pdo_max, op, max);
990990+ break;
991991+ default:
992992+ return -EINVAL;
993993+ }
994994+995995+ return 0;
996996+}
997997+998998+#define min_power(x, y) min(pdo_max_power(x), pdo_max_power(y))
999999+#define min_current(x, y) min(pdo_max_current(x), pdo_max_current(y))
10001000+10011001+static int tcpm_pd_select_pdo(struct udevice *dev, int *sink_pdo,
10021002+ int *src_pdo)
10031003+{
10041004+ struct tcpm_port *port = dev_get_uclass_plat(dev);
10051005+ unsigned int i, j, max_src_mv = 0, min_src_mv = 0, max_mw = 0,
10061006+ max_mv = 0, src_mw = 0, src_ma = 0, max_snk_mv = 0,
10071007+ min_snk_mv = 0;
10081008+ int ret = -EINVAL;
10091009+10101010+ /*
10111011+ * Select the source PDO providing the most power which has a
10121012+ * matchig sink cap.
10131013+ */
10141014+ for (i = 0; i < port->nr_source_caps; i++) {
10151015+ u32 pdo = port->source_caps[i];
10161016+ enum pd_pdo_type type = pdo_type(pdo);
10171017+10181018+ switch (type) {
10191019+ case PDO_TYPE_FIXED:
10201020+ max_src_mv = pdo_fixed_voltage(pdo);
10211021+ min_src_mv = max_src_mv;
10221022+ break;
10231023+ case PDO_TYPE_BATT:
10241024+ case PDO_TYPE_VAR:
10251025+ max_src_mv = pdo_max_voltage(pdo);
10261026+ min_src_mv = pdo_min_voltage(pdo);
10271027+ break;
10281028+ case PDO_TYPE_APDO:
10291029+ continue;
10301030+ default:
10311031+ dev_err(dev, "TCPM: Invalid source PDO type, ignoring\n");
10321032+ continue;
10331033+ }
10341034+10351035+ switch (type) {
10361036+ case PDO_TYPE_FIXED:
10371037+ case PDO_TYPE_VAR:
10381038+ src_ma = pdo_max_current(pdo);
10391039+ src_mw = src_ma * min_src_mv / 1000;
10401040+ break;
10411041+ case PDO_TYPE_BATT:
10421042+ src_mw = pdo_max_power(pdo);
10431043+ break;
10441044+ case PDO_TYPE_APDO:
10451045+ continue;
10461046+ default:
10471047+ dev_err(dev, "TCPM: Invalid source PDO type, ignoring\n");
10481048+ continue;
10491049+ }
10501050+10511051+ for (j = 0; j < port->nr_snk_pdo; j++) {
10521052+ pdo = port->snk_pdo[j];
10531053+10541054+ switch (pdo_type(pdo)) {
10551055+ case PDO_TYPE_FIXED:
10561056+ max_snk_mv = pdo_fixed_voltage(pdo);
10571057+ min_snk_mv = max_snk_mv;
10581058+ break;
10591059+ case PDO_TYPE_BATT:
10601060+ case PDO_TYPE_VAR:
10611061+ max_snk_mv = pdo_max_voltage(pdo);
10621062+ min_snk_mv = pdo_min_voltage(pdo);
10631063+ break;
10641064+ case PDO_TYPE_APDO:
10651065+ continue;
10661066+ default:
10671067+ dev_err(dev, "TCPM: Invalid sink PDO type, ignoring\n");
10681068+ continue;
10691069+ }
10701070+10711071+ if (max_src_mv <= max_snk_mv && min_src_mv >= min_snk_mv) {
10721072+ /* Prefer higher voltages if available */
10731073+ if ((src_mw == max_mw && min_src_mv > max_mv) ||
10741074+ src_mw > max_mw) {
10751075+ *src_pdo = i;
10761076+ *sink_pdo = j;
10771077+ max_mw = src_mw;
10781078+ max_mv = min_src_mv;
10791079+ ret = 0;
10801080+ }
10811081+ }
10821082+ }
10831083+ }
10841084+10851085+ return ret;
10861086+}
10871087+10881088+static int tcpm_pd_build_request(struct udevice *dev, u32 *rdo)
10891089+{
10901090+ struct tcpm_port *port = dev_get_uclass_plat(dev);
10911091+ unsigned int mv, ma, mw, flags;
10921092+ unsigned int max_ma, max_mw;
10931093+ enum pd_pdo_type type;
10941094+ u32 pdo, matching_snk_pdo;
10951095+ int src_pdo_index = 0;
10961096+ int snk_pdo_index = 0;
10971097+ int ret;
10981098+10991099+ ret = tcpm_pd_select_pdo(dev, &snk_pdo_index, &src_pdo_index);
11001100+ if (ret < 0)
11011101+ return ret;
11021102+11031103+ pdo = port->source_caps[src_pdo_index];
11041104+ matching_snk_pdo = port->snk_pdo[snk_pdo_index];
11051105+ type = pdo_type(pdo);
11061106+11071107+ switch (type) {
11081108+ case PDO_TYPE_FIXED:
11091109+ mv = pdo_fixed_voltage(pdo);
11101110+ break;
11111111+ case PDO_TYPE_BATT:
11121112+ case PDO_TYPE_VAR:
11131113+ mv = pdo_min_voltage(pdo);
11141114+ break;
11151115+ default:
11161116+ dev_err(dev, "TCPM: Invalid PDO selected!\n");
11171117+ return -EINVAL;
11181118+ }
11191119+11201120+ /* Select maximum available current within the sink pdo's limit */
11211121+ if (type == PDO_TYPE_BATT) {
11221122+ mw = min_power(pdo, matching_snk_pdo);
11231123+ ma = 1000 * mw / mv;
11241124+ } else {
11251125+ ma = min_current(pdo, matching_snk_pdo);
11261126+ mw = ma * mv / 1000;
11271127+ }
11281128+11291129+ flags = RDO_USB_COMM | RDO_NO_SUSPEND;
11301130+11311131+ /* Set mismatch bit if offered power is less than operating power */
11321132+ max_ma = ma;
11331133+ max_mw = mw;
11341134+ if (mw < port->operating_snk_mw) {
11351135+ flags |= RDO_CAP_MISMATCH;
11361136+ if (type == PDO_TYPE_BATT &&
11371137+ (pdo_max_power(matching_snk_pdo) > pdo_max_power(pdo)))
11381138+ max_mw = pdo_max_power(matching_snk_pdo);
11391139+ else if (pdo_max_current(matching_snk_pdo) >
11401140+ pdo_max_current(pdo))
11411141+ max_ma = pdo_max_current(matching_snk_pdo);
11421142+ }
11431143+11441144+ dev_dbg(dev, "TCPM: cc=%d cc1=%d cc2=%d vbus=%d vconn=%s polarity=%d\n",
11451145+ port->cc_req, port->cc1, port->cc2, port->vbus_source,
11461146+ port->vconn_role == TYPEC_SOURCE ? "source" : "sink",
11471147+ port->polarity);
11481148+11491149+ if (type == PDO_TYPE_BATT) {
11501150+ *rdo = RDO_BATT(src_pdo_index + 1, mw, max_mw, flags);
11511151+11521152+ dev_info(dev, "TCPM: requesting PDO %d: %u mV, %u mW%s\n",
11531153+ src_pdo_index, mv, mw,
11541154+ flags & RDO_CAP_MISMATCH ? " [mismatch]" : "");
11551155+ } else {
11561156+ *rdo = RDO_FIXED(src_pdo_index + 1, ma, max_ma, flags);
11571157+11581158+ dev_info(dev, "TCPM: requesting PDO %d: %u mV, %u mA%s\n",
11591159+ src_pdo_index, mv, ma,
11601160+ flags & RDO_CAP_MISMATCH ? " [mismatch]" : "");
11611161+ }
11621162+11631163+ port->req_current_limit = ma;
11641164+ port->req_supply_voltage = mv;
11651165+11661166+ return 0;
11671167+}
11681168+11691169+static int tcpm_pd_send_request(struct udevice *dev)
11701170+{
11711171+ struct tcpm_port *port = dev_get_uclass_plat(dev);
11721172+ struct pd_message msg;
11731173+ int ret;
11741174+ u32 rdo;
11751175+11761176+ ret = tcpm_pd_build_request(dev, &rdo);
11771177+ if (ret < 0)
11781178+ return ret;
11791179+11801180+ memset(&msg, 0, sizeof(msg));
11811181+ msg.header = PD_HEADER_LE(PD_DATA_REQUEST,
11821182+ port->pwr_role,
11831183+ port->data_role,
11841184+ port->negotiated_rev,
11851185+ port->message_id, 1);
11861186+ msg.payload[0] = cpu_to_le32(rdo);
11871187+11881188+ return tcpm_pd_transmit(dev, TCPC_TX_SOP, &msg);
11891189+}
11901190+11911191+static int tcpm_set_vbus(struct udevice *dev, bool enable)
11921192+{
11931193+ struct tcpm_port *port = dev_get_uclass_plat(dev);
11941194+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
11951195+ int ret;
11961196+11971197+ if (enable && port->vbus_charge)
11981198+ return -EINVAL;
11991199+12001200+ dev_dbg(dev, "TCPM: set vbus = %d charge = %d\n",
12011201+ enable, port->vbus_charge);
12021202+12031203+ ret = drvops->set_vbus(dev, enable, port->vbus_charge);
12041204+ if (ret < 0)
12051205+ return ret;
12061206+12071207+ port->vbus_source = enable;
12081208+ return 0;
12091209+}
12101210+12111211+static int tcpm_set_charge(struct udevice *dev, bool charge)
12121212+{
12131213+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
12141214+ struct tcpm_port *port = dev_get_uclass_plat(dev);
12151215+ int ret;
12161216+12171217+ if (charge && port->vbus_source)
12181218+ return -EINVAL;
12191219+12201220+ if (charge != port->vbus_charge) {
12211221+ dev_dbg(dev, "TCPM: set vbus = %d charge = %d\n",
12221222+ port->vbus_source, charge);
12231223+ ret = drvops->set_vbus(dev, port->vbus_source,
12241224+ charge);
12251225+ if (ret < 0)
12261226+ return ret;
12271227+ }
12281228+ port->vbus_charge = charge;
12291229+ return 0;
12301230+}
12311231+12321232+static bool tcpm_start_toggling(struct udevice *dev, enum typec_cc_status cc)
12331233+{
12341234+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
12351235+ struct tcpm_port *port = dev_get_uclass_plat(dev);
12361236+ int ret;
12371237+12381238+ if (!drvops->start_toggling)
12391239+ return false;
12401240+12411241+ dev_dbg(dev, "TCPM: Start toggling\n");
12421242+ ret = drvops->start_toggling(dev, port->port_type, cc);
12431243+ return ret == 0;
12441244+}
12451245+12461246+static int tcpm_init_vbus(struct udevice *dev)
12471247+{
12481248+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
12491249+ struct tcpm_port *port = dev_get_uclass_plat(dev);
12501250+ int ret;
12511251+12521252+ ret = drvops->set_vbus(dev, false, false);
12531253+ port->vbus_source = false;
12541254+ port->vbus_charge = false;
12551255+ return ret;
12561256+}
12571257+12581258+static int tcpm_init_vconn(struct udevice *dev)
12591259+{
12601260+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
12611261+ struct tcpm_port *port = dev_get_uclass_plat(dev);
12621262+ int ret;
12631263+12641264+ ret = drvops->set_vconn(dev, false);
12651265+ port->vconn_role = TYPEC_SINK;
12661266+ return ret;
12671267+}
12681268+12691269+static inline void tcpm_typec_connect(struct tcpm_port *port)
12701270+{
12711271+ if (!port->connected)
12721272+ port->connected = true;
12731273+}
12741274+12751275+static int tcpm_src_attach(struct udevice *dev)
12761276+{
12771277+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
12781278+ struct tcpm_port *port = dev_get_uclass_plat(dev);
12791279+ enum typec_cc_polarity polarity =
12801280+ port->cc2 == TYPEC_CC_RD ? TYPEC_POLARITY_CC2
12811281+ : TYPEC_POLARITY_CC1;
12821282+ int ret;
12831283+12841284+ if (port->attached)
12851285+ return 0;
12861286+12871287+ ret = tcpm_set_polarity(dev, polarity);
12881288+ if (ret < 0)
12891289+ return ret;
12901290+12911291+ ret = tcpm_set_roles(dev, true, TYPEC_SOURCE, TYPEC_HOST);
12921292+ if (ret < 0)
12931293+ return ret;
12941294+12951295+ ret = drvops->set_pd_rx(dev, true);
12961296+ if (ret < 0)
12971297+ goto out_disable_mux;
12981298+12991299+ /*
13001300+ * USB Type-C specification, version 1.2,
13011301+ * chapter 4.5.2.2.8.1 (Attached.SRC Requirements)
13021302+ * Enable VCONN only if the non-RD port is set to RA.
13031303+ */
13041304+ if ((polarity == TYPEC_POLARITY_CC1 && port->cc2 == TYPEC_CC_RA) ||
13051305+ (polarity == TYPEC_POLARITY_CC2 && port->cc1 == TYPEC_CC_RA)) {
13061306+ ret = tcpm_set_vconn(dev, true);
13071307+ if (ret < 0)
13081308+ goto out_disable_pd;
13091309+ }
13101310+13111311+ ret = tcpm_set_vbus(dev, true);
13121312+ if (ret < 0)
13131313+ goto out_disable_vconn;
13141314+13151315+ port->pd_capable = false;
13161316+13171317+ port->partner = NULL;
13181318+13191319+ port->attached = true;
13201320+13211321+ return 0;
13221322+13231323+out_disable_vconn:
13241324+ tcpm_set_vconn(dev, false);
13251325+out_disable_pd:
13261326+ drvops->set_pd_rx(dev, false);
13271327+out_disable_mux:
13281328+ dev_err(dev, "TCPM: CC connected in %s as DFP\n",
13291329+ polarity ? "CC2" : "CC1");
13301330+ return 0;
13311331+}
13321332+13331333+static inline void tcpm_typec_disconnect(struct tcpm_port *port)
13341334+{
13351335+ if (port->connected) {
13361336+ port->partner = NULL;
13371337+ port->connected = false;
13381338+ }
13391339+}
13401340+13411341+static void tcpm_reset_port(struct udevice *dev)
13421342+{
13431343+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
13441344+ struct tcpm_port *port = dev_get_uclass_plat(dev);
13451345+13461346+ tcpm_timer_uninit(dev);
13471347+ tcpm_typec_disconnect(port);
13481348+ tcpm_reset_event_cnt(dev);
13491349+ port->wait_dr_swap_message = false;
13501350+ port->attached = false;
13511351+ port->pd_capable = false;
13521352+13531353+ /*
13541354+ * First Rx ID should be 0; set this to a sentinel of -1 so that
13551355+ * we can check tcpm_pd_rx_handler() if we had seen it before.
13561356+ */
13571357+ port->rx_msgid = -1;
13581358+13591359+ drvops->set_pd_rx(dev, false);
13601360+ tcpm_init_vbus(dev); /* also disables charging */
13611361+ tcpm_init_vconn(dev);
13621362+ tcpm_set_current_limit(dev, 0, 0);
13631363+ tcpm_set_polarity(dev, TYPEC_POLARITY_CC1);
13641364+ tcpm_set_attached_state(dev, false);
13651365+ port->nr_sink_caps = 0;
13661366+}
13671367+13681368+static void tcpm_detach(struct udevice *dev)
13691369+{
13701370+ struct tcpm_port *port = dev_get_uclass_plat(dev);
13711371+13721372+ if (tcpm_port_is_disconnected(port))
13731373+ port->hard_reset_count = 0;
13741374+13751375+ if (!port->attached)
13761376+ return;
13771377+13781378+ tcpm_reset_port(dev);
13791379+}
13801380+13811381+static void tcpm_src_detach(struct udevice *dev)
13821382+{
13831383+ tcpm_detach(dev);
13841384+}
13851385+13861386+static int tcpm_snk_attach(struct udevice *dev)
13871387+{
13881388+ struct tcpm_port *port = dev_get_uclass_plat(dev);
13891389+ int ret;
13901390+13911391+ if (port->attached)
13921392+ return 0;
13931393+13941394+ ret = tcpm_set_polarity(dev, port->cc2 != TYPEC_CC_OPEN ?
13951395+ TYPEC_POLARITY_CC2 : TYPEC_POLARITY_CC1);
13961396+ if (ret < 0)
13971397+ return ret;
13981398+13991399+ ret = tcpm_set_roles(dev, true, TYPEC_SINK, TYPEC_DEVICE);
14001400+ if (ret < 0)
14011401+ return ret;
14021402+14031403+ port->pd_capable = false;
14041404+14051405+ port->partner = NULL;
14061406+14071407+ port->attached = true;
14081408+ dev_info(dev, "TCPM: CC connected in %s as UFP\n",
14091409+ port->cc1 != TYPEC_CC_OPEN ? "CC1" : "CC2");
14101410+14111411+ return 0;
14121412+}
14131413+14141414+static void tcpm_snk_detach(struct udevice *dev)
14151415+{
14161416+ tcpm_detach(dev);
14171417+}
14181418+14191419+static inline enum tcpm_state hard_reset_state(struct tcpm_port *port)
14201420+{
14211421+ if (port->hard_reset_count < PD_N_HARD_RESET_COUNT)
14221422+ return HARD_RESET_SEND;
14231423+ if (port->pd_capable)
14241424+ return ERROR_RECOVERY;
14251425+ if (port->pwr_role == TYPEC_SOURCE)
14261426+ return SRC_UNATTACHED;
14271427+ if (port->state == SNK_WAIT_CAPABILITIES)
14281428+ return SNK_READY;
14291429+ return SNK_UNATTACHED;
14301430+}
14311431+14321432+static inline enum tcpm_state unattached_state(struct tcpm_port *port)
14331433+{
14341434+ if (port->port_type == TYPEC_PORT_DRP) {
14351435+ if (port->pwr_role == TYPEC_SOURCE)
14361436+ return SRC_UNATTACHED;
14371437+ else
14381438+ return SNK_UNATTACHED;
14391439+ } else if (port->port_type == TYPEC_PORT_SRC) {
14401440+ return SRC_UNATTACHED;
14411441+ }
14421442+14431443+ return SNK_UNATTACHED;
14441444+}
14451445+14461446+static void run_state_machine(struct udevice *dev)
14471447+{
14481448+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
14491449+ struct tcpm_port *port = dev_get_uclass_plat(dev);
14501450+ int ret;
14511451+14521452+ port->enter_state = port->state;
14531453+ switch (port->state) {
14541454+ case TOGGLING:
14551455+ break;
14561456+ /* SRC states */
14571457+ case SRC_UNATTACHED:
14581458+ tcpm_src_detach(dev);
14591459+ if (tcpm_start_toggling(dev, tcpm_rp_cc(port))) {
14601460+ tcpm_set_state(dev, TOGGLING, 0);
14611461+ break;
14621462+ }
14631463+ tcpm_set_cc(dev, tcpm_rp_cc(port));
14641464+ if (port->port_type == TYPEC_PORT_DRP)
14651465+ tcpm_set_state(dev, SNK_UNATTACHED, PD_T_DRP_SNK);
14661466+ break;
14671467+ case SRC_ATTACH_WAIT:
14681468+ if (tcpm_port_is_source(port))
14691469+ tcpm_set_state(dev, SRC_ATTACHED, PD_T_CC_DEBOUNCE);
14701470+ break;
14711471+14721472+ case SRC_ATTACHED:
14731473+ ret = tcpm_src_attach(dev);
14741474+ /*
14751475+ * Currently, vbus control is not implemented,
14761476+ * and the SRC detection process cannot be fully implemented.
14771477+ */
14781478+ tcpm_set_state(dev, SRC_READY, 0);
14791479+ break;
14801480+ case SRC_STARTUP:
14811481+ port->caps_count = 0;
14821482+ port->negotiated_rev = PD_MAX_REV;
14831483+ port->message_id = 0;
14841484+ port->rx_msgid = -1;
14851485+ port->explicit_contract = false;
14861486+ tcpm_set_state(dev, SRC_SEND_CAPABILITIES, 0);
14871487+ break;
14881488+ case SRC_SEND_CAPABILITIES:
14891489+ port->caps_count++;
14901490+ if (port->caps_count > PD_N_CAPS_COUNT) {
14911491+ tcpm_set_state(dev, SRC_READY, 0);
14921492+ break;
14931493+ }
14941494+ ret = tcpm_pd_send_source_caps(dev);
14951495+ if (ret < 0) {
14961496+ tcpm_set_state(dev, SRC_SEND_CAPABILITIES,
14971497+ PD_T_SEND_SOURCE_CAP);
14981498+ } else {
14991499+ /*
15001500+ * Per standard, we should clear the reset counter here.
15011501+ * However, that can result in state machine hang-ups.
15021502+ * Reset it only in READY state to improve stability.
15031503+ */
15041504+ /* port->hard_reset_count = 0; */
15051505+ port->caps_count = 0;
15061506+ port->pd_capable = true;
15071507+ tcpm_set_state_cond(dev, SRC_SEND_CAPABILITIES_TIMEOUT,
15081508+ PD_T_SEND_SOURCE_CAP);
15091509+ }
15101510+ break;
15111511+ case SRC_SEND_CAPABILITIES_TIMEOUT:
15121512+ /*
15131513+ * Error recovery for a PD_DATA_SOURCE_CAP reply timeout.
15141514+ *
15151515+ * PD 2.0 sinks are supposed to accept src-capabilities with a
15161516+ * 3.0 header and simply ignore any src PDOs which the sink does
15171517+ * not understand such as PPS but some 2.0 sinks instead ignore
15181518+ * the entire PD_DATA_SOURCE_CAP message, causing contract
15191519+ * negotiation to fail.
15201520+ *
15211521+ * After PD_N_HARD_RESET_COUNT hard-reset attempts, we try
15221522+ * sending src-capabilities with a lower PD revision to
15231523+ * make these broken sinks work.
15241524+ */
15251525+ if (port->hard_reset_count < PD_N_HARD_RESET_COUNT) {
15261526+ tcpm_set_state(dev, HARD_RESET_SEND, 0);
15271527+ } else if (port->negotiated_rev > PD_REV20) {
15281528+ port->negotiated_rev--;
15291529+ port->hard_reset_count = 0;
15301530+ tcpm_set_state(dev, SRC_SEND_CAPABILITIES, 0);
15311531+ } else {
15321532+ tcpm_set_state(dev, hard_reset_state(port), 0);
15331533+ }
15341534+ break;
15351535+ case SRC_NEGOTIATE_CAPABILITIES:
15361536+ ret = tcpm_pd_check_request(dev);
15371537+ if (ret < 0) {
15381538+ tcpm_pd_send_control(dev, PD_CTRL_REJECT);
15391539+ if (!port->explicit_contract) {
15401540+ tcpm_set_state(dev,
15411541+ SRC_WAIT_NEW_CAPABILITIES, 0);
15421542+ } else {
15431543+ tcpm_set_state(dev, SRC_READY, 0);
15441544+ }
15451545+ } else {
15461546+ tcpm_pd_send_control(dev, PD_CTRL_ACCEPT);
15471547+ tcpm_set_state(dev, SRC_TRANSITION_SUPPLY,
15481548+ PD_T_SRC_TRANSITION);
15491549+ }
15501550+ break;
15511551+ case SRC_TRANSITION_SUPPLY:
15521552+ /* XXX: regulator_set_voltage(vbus, ...) */
15531553+ tcpm_pd_send_control(dev, PD_CTRL_PS_RDY);
15541554+ port->explicit_contract = true;
15551555+ tcpm_set_state_cond(dev, SRC_READY, 0);
15561556+ break;
15571557+ case SRC_READY:
15581558+ port->hard_reset_count = 0;
15591559+15601560+ tcpm_typec_connect(port);
15611561+ break;
15621562+ case SRC_WAIT_NEW_CAPABILITIES:
15631563+ /* Nothing to do... */
15641564+ break;
15651565+15661566+ /* SNK states */
15671567+ case SNK_UNATTACHED:
15681568+ tcpm_snk_detach(dev);
15691569+ if (tcpm_start_toggling(dev, TYPEC_CC_RD)) {
15701570+ tcpm_set_state(dev, TOGGLING, 0);
15711571+ break;
15721572+ }
15731573+ tcpm_set_cc(dev, TYPEC_CC_RD);
15741574+ if (port->port_type == TYPEC_PORT_DRP)
15751575+ tcpm_set_state(dev, SRC_UNATTACHED, PD_T_DRP_SRC);
15761576+ break;
15771577+ case SNK_ATTACH_WAIT:
15781578+ if ((port->cc1 == TYPEC_CC_OPEN &&
15791579+ port->cc2 != TYPEC_CC_OPEN) ||
15801580+ (port->cc1 != TYPEC_CC_OPEN &&
15811581+ port->cc2 == TYPEC_CC_OPEN))
15821582+ tcpm_set_state(dev, SNK_DEBOUNCED,
15831583+ PD_T_CC_DEBOUNCE);
15841584+ else if (tcpm_port_is_disconnected(port))
15851585+ tcpm_set_state(dev, SNK_UNATTACHED,
15861586+ PD_T_CC_DEBOUNCE);
15871587+ break;
15881588+ case SNK_DEBOUNCED:
15891589+ if (tcpm_port_is_disconnected(port))
15901590+ tcpm_set_state(dev, SNK_UNATTACHED, PD_T_PD_DEBOUNCE);
15911591+ else if (port->vbus_present)
15921592+ tcpm_set_state(dev, SNK_ATTACHED, 0);
15931593+ else
15941594+ /* Wait for VBUS, but not forever */
15951595+ tcpm_set_state(dev, PORT_RESET, PD_T_PS_SOURCE_ON);
15961596+ break;
15971597+ case SNK_ATTACHED:
15981598+ ret = tcpm_snk_attach(dev);
15991599+ if (ret < 0)
16001600+ tcpm_set_state(dev, SNK_UNATTACHED, 0);
16011601+ else
16021602+ tcpm_set_state(dev, SNK_STARTUP, 0);
16031603+ break;
16041604+ case SNK_STARTUP:
16051605+ port->negotiated_rev = PD_MAX_REV;
16061606+ port->message_id = 0;
16071607+ port->rx_msgid = -1;
16081608+ port->explicit_contract = false;
16091609+ tcpm_set_state(dev, SNK_DISCOVERY, 0);
16101610+ break;
16111611+ case SNK_DISCOVERY:
16121612+ if (port->vbus_present) {
16131613+ tcpm_set_current_limit(dev,
16141614+ tcpm_get_current_limit(port),
16151615+ 5000);
16161616+ tcpm_set_charge(dev, true);
16171617+ tcpm_set_state(dev, SNK_WAIT_CAPABILITIES, 0);
16181618+ break;
16191619+ }
16201620+ /*
16211621+ * For DRP, timeouts differ. Also, handling is supposed to be
16221622+ * different and much more complex (dead battery detection;
16231623+ * see USB power delivery specification, section 8.3.3.6.1.5.1).
16241624+ */
16251625+ tcpm_set_state(dev, hard_reset_state(port),
16261626+ port->port_type == TYPEC_PORT_DRP ?
16271627+ PD_T_DB_DETECT : PD_T_NO_RESPONSE);
16281628+ break;
16291629+ case SNK_DISCOVERY_DEBOUNCE:
16301630+ tcpm_set_state(dev, SNK_DISCOVERY_DEBOUNCE_DONE,
16311631+ PD_T_CC_DEBOUNCE);
16321632+ break;
16331633+ case SNK_DISCOVERY_DEBOUNCE_DONE:
16341634+ tcpm_set_state(dev, unattached_state(port), 0);
16351635+ break;
16361636+ case SNK_WAIT_CAPABILITIES:
16371637+ ret = drvops->set_pd_rx(dev, true);
16381638+ if (ret < 0) {
16391639+ tcpm_set_state(dev, SNK_READY, 0);
16401640+ break;
16411641+ }
16421642+ /*
16431643+ * If VBUS has never been low, and we time out waiting
16441644+ * for source cap, try a soft reset first, in case we
16451645+ * were already in a stable contract before this boot.
16461646+ * Do this only once.
16471647+ */
16481648+ if (port->vbus_never_low) {
16491649+ port->vbus_never_low = false;
16501650+ tcpm_set_state(dev, SOFT_RESET_SEND,
16511651+ PD_T_SINK_WAIT_CAP);
16521652+ } else {
16531653+ tcpm_set_state(dev, hard_reset_state(port),
16541654+ PD_T_SINK_WAIT_CAP);
16551655+ }
16561656+ break;
16571657+ case SNK_NEGOTIATE_CAPABILITIES:
16581658+ port->pd_capable = true;
16591659+ port->hard_reset_count = 0;
16601660+ ret = tcpm_pd_send_request(dev);
16611661+ if (ret < 0) {
16621662+ /* Let the Source send capabilities again. */
16631663+ tcpm_set_state(dev, SNK_WAIT_CAPABILITIES, 0);
16641664+ } else {
16651665+ tcpm_set_state_cond(dev, hard_reset_state(port),
16661666+ PD_T_SENDER_RESPONSE);
16671667+ }
16681668+ break;
16691669+ case SNK_TRANSITION_SINK:
16701670+ case SNK_TRANSITION_SINK_VBUS:
16711671+ tcpm_set_state(dev, hard_reset_state(port),
16721672+ PD_T_PS_TRANSITION);
16731673+ break;
16741674+ case SNK_READY:
16751675+ port->update_sink_caps = false;
16761676+ tcpm_typec_connect(port);
16771677+ /*
16781678+ * Here poll_event_cnt is cleared, waiting for self-powered Type-C devices
16791679+ * to send DR_swap Messge until 1s (TCPM_POLL_EVENT_TIME_OUT * 500us)timeout
16801680+ */
16811681+ if (port->wait_dr_swap_message)
16821682+ tcpm_reset_event_cnt(dev);
16831683+16841684+ break;
16851685+16861686+ /* Hard_Reset states */
16871687+ case HARD_RESET_SEND:
16881688+ tcpm_pd_transmit(dev, TCPC_TX_HARD_RESET, NULL);
16891689+ tcpm_set_state(dev, HARD_RESET_START, 0);
16901690+ port->wait_dr_swap_message = false;
16911691+ break;
16921692+ case HARD_RESET_START:
16931693+ port->hard_reset_count++;
16941694+ drvops->set_pd_rx(dev, false);
16951695+ port->nr_sink_caps = 0;
16961696+ if (port->pwr_role == TYPEC_SOURCE)
16971697+ tcpm_set_state(dev, SRC_HARD_RESET_VBUS_OFF,
16981698+ PD_T_PS_HARD_RESET);
16991699+ else
17001700+ tcpm_set_state(dev, SNK_HARD_RESET_SINK_OFF, 0);
17011701+ break;
17021702+ case SRC_HARD_RESET_VBUS_OFF:
17031703+ tcpm_set_vconn(dev, true);
17041704+ tcpm_set_vbus(dev, false);
17051705+ tcpm_set_roles(dev, port->self_powered, TYPEC_SOURCE,
17061706+ TYPEC_HOST);
17071707+ tcpm_set_state(dev, SRC_HARD_RESET_VBUS_ON, PD_T_SRC_RECOVER);
17081708+ break;
17091709+ case SRC_HARD_RESET_VBUS_ON:
17101710+ tcpm_set_vconn(dev, true);
17111711+ tcpm_set_vbus(dev, true);
17121712+ drvops->set_pd_rx(dev, true);
17131713+ tcpm_set_attached_state(dev, true);
17141714+ tcpm_set_state(dev, SRC_UNATTACHED, PD_T_PS_SOURCE_ON);
17151715+ break;
17161716+ case SNK_HARD_RESET_SINK_OFF:
17171717+ tcpm_set_vconn(dev, false);
17181718+ if (port->pd_capable)
17191719+ tcpm_set_charge(dev, false);
17201720+ tcpm_set_roles(dev, port->self_powered, TYPEC_SINK,
17211721+ TYPEC_DEVICE);
17221722+ /*
17231723+ * VBUS may or may not toggle, depending on the adapter.
17241724+ * If it doesn't toggle, transition to SNK_HARD_RESET_SINK_ON
17251725+ * directly after timeout.
17261726+ */
17271727+ tcpm_set_state(dev, SNK_HARD_RESET_SINK_ON, PD_T_SAFE_0V);
17281728+ break;
17291729+ case SNK_HARD_RESET_WAIT_VBUS:
17301730+ /* Assume we're disconnected if VBUS doesn't come back. */
17311731+ tcpm_set_state(dev, SNK_UNATTACHED,
17321732+ PD_T_SRC_RECOVER_MAX + PD_T_SRC_TURN_ON);
17331733+ break;
17341734+ case SNK_HARD_RESET_SINK_ON:
17351735+ /* Note: There is no guarantee that VBUS is on in this state */
17361736+ /*
17371737+ * XXX:
17381738+ * The specification suggests that dual mode ports in sink
17391739+ * mode should transition to state PE_SRC_Transition_to_default.
17401740+ * See USB power delivery specification chapter 8.3.3.6.1.3.
17411741+ * This would mean to
17421742+ * - turn off VCONN, reset power supply
17431743+ * - request hardware reset
17441744+ * - turn on VCONN
17451745+ * - Transition to state PE_Src_Startup
17461746+ * SNK only ports shall transition to state Snk_Startup
17471747+ * (see chapter 8.3.3.3.8).
17481748+ * Similar, dual-mode ports in source mode should transition
17491749+ * to PE_SNK_Transition_to_default.
17501750+ */
17511751+ if (port->pd_capable) {
17521752+ tcpm_set_current_limit(dev,
17531753+ tcpm_get_current_limit(port),
17541754+ 5000);
17551755+ tcpm_set_charge(dev, true);
17561756+ }
17571757+ tcpm_set_attached_state(dev, true);
17581758+ tcpm_set_state(dev, SNK_STARTUP, 0);
17591759+ break;
17601760+17611761+ /* Soft_Reset states */
17621762+ case SOFT_RESET:
17631763+ port->message_id = 0;
17641764+ port->rx_msgid = -1;
17651765+ tcpm_pd_send_control(dev, PD_CTRL_ACCEPT);
17661766+ if (port->pwr_role == TYPEC_SOURCE)
17671767+ tcpm_set_state(dev, SRC_SEND_CAPABILITIES, 0);
17681768+ else
17691769+ tcpm_set_state(dev, SNK_WAIT_CAPABILITIES, 0);
17701770+ break;
17711771+ case SOFT_RESET_SEND:
17721772+ port->message_id = 0;
17731773+ port->rx_msgid = -1;
17741774+ if (tcpm_pd_send_control(dev, PD_CTRL_SOFT_RESET))
17751775+ tcpm_set_state_cond(dev, hard_reset_state(port), 0);
17761776+ else
17771777+ tcpm_set_state_cond(dev, hard_reset_state(port),
17781778+ PD_T_SENDER_RESPONSE);
17791779+ break;
17801780+17811781+ /* DR_Swap states */
17821782+ case DR_SWAP_ACCEPT:
17831783+ tcpm_pd_send_control(dev, PD_CTRL_ACCEPT);
17841784+ tcpm_set_state_cond(dev, DR_SWAP_CHANGE_DR, 0);
17851785+ break;
17861786+ case DR_SWAP_CHANGE_DR:
17871787+ if (port->data_role == TYPEC_HOST) {
17881788+ tcpm_set_roles(dev, true, port->pwr_role,
17891789+ TYPEC_DEVICE);
17901790+ } else {
17911791+ tcpm_set_roles(dev, true, port->pwr_role,
17921792+ TYPEC_HOST);
17931793+ }
17941794+ /* DR_swap process complete, wait_dr_swap_message is cleared */
17951795+ port->wait_dr_swap_message = false;
17961796+ tcpm_set_state(dev, ready_state(port), 0);
17971797+ break;
17981798+ case ERROR_RECOVERY:
17991799+ tcpm_set_state(dev, PORT_RESET, 0);
18001800+ break;
18011801+ case PORT_RESET:
18021802+ tcpm_reset_port(dev);
18031803+ if (port->self_powered)
18041804+ tcpm_set_cc(dev, TYPEC_CC_OPEN);
18051805+ else
18061806+ tcpm_set_cc(dev, tcpm_default_state(port) == SNK_UNATTACHED ?
18071807+ TYPEC_CC_RD : tcpm_rp_cc(port));
18081808+ tcpm_set_state(dev, PORT_RESET_WAIT_OFF,
18091809+ PD_T_ERROR_RECOVERY);
18101810+ break;
18111811+ case PORT_RESET_WAIT_OFF:
18121812+ tcpm_set_state(dev,
18131813+ tcpm_default_state(port),
18141814+ port->vbus_present ? PD_T_PS_SOURCE_OFF : 0);
18151815+ break;
18161816+ default:
18171817+ dev_err(dev, "TCPM: Unexpected port state %d\n", port->state);
18181818+ break;
18191819+ }
18201820+}
18211821+18221822+static void tcpm_state_machine(struct udevice *dev)
18231823+{
18241824+ struct tcpm_port *port = dev_get_uclass_plat(dev);
18251825+ enum tcpm_state prev_state;
18261826+18271827+ mutex_lock(&port->lock);
18281828+ port->state_machine_running = true;
18291829+18301830+ if (port->queued_message && tcpm_send_queued_message(dev))
18311831+ goto done;
18321832+18331833+ /* If we were queued due to a delayed state change, update it now */
18341834+ if (port->delayed_state) {
18351835+ dev_dbg(dev, "TCPM: state change %s -> %s [delayed %ld ms]\n",
18361836+ tcpm_states[port->state],
18371837+ tcpm_states[port->delayed_state], port->delay_ms);
18381838+ port->prev_state = port->state;
18391839+ port->state = port->delayed_state;
18401840+ port->delayed_state = INVALID_STATE;
18411841+ }
18421842+18431843+ /*
18441844+ * Continue running as long as we have (non-delayed) state changes
18451845+ * to make.
18461846+ */
18471847+ do {
18481848+ prev_state = port->state;
18491849+ run_state_machine(dev);
18501850+ if (port->queued_message)
18511851+ tcpm_send_queued_message(dev);
18521852+ } while (port->state != prev_state && !port->delayed_state);
18531853+18541854+done:
18551855+ port->state_machine_running = false;
18561856+ mutex_unlock(&port->lock);
18571857+}
18581858+18591859+static void _tcpm_cc_change(struct udevice *dev, enum typec_cc_status cc1,
18601860+ enum typec_cc_status cc2)
18611861+{
18621862+ struct tcpm_port *port = dev_get_uclass_plat(dev);
18631863+ enum typec_cc_status old_cc1, old_cc2;
18641864+ enum tcpm_state new_state;
18651865+18661866+ old_cc1 = port->cc1;
18671867+ old_cc2 = port->cc2;
18681868+ port->cc1 = cc1;
18691869+ port->cc2 = cc2;
18701870+18711871+ dev_dbg(dev, "TCPM: CC1: %u -> %u, CC2: %u -> %u [state %s, polarity %d, %s]\n",
18721872+ old_cc1, cc1, old_cc2, cc2, tcpm_states[port->state],
18731873+ port->polarity,
18741874+ tcpm_port_is_disconnected(port) ? "disconnected" : "connected");
18751875+18761876+ switch (port->state) {
18771877+ case TOGGLING:
18781878+ if (tcpm_port_is_source(port))
18791879+ tcpm_set_state(dev, SRC_ATTACH_WAIT, 0);
18801880+ else if (tcpm_port_is_sink(port))
18811881+ tcpm_set_state(dev, SNK_ATTACH_WAIT, 0);
18821882+ break;
18831883+ case SRC_UNATTACHED:
18841884+ case SRC_ATTACH_WAIT:
18851885+ if (tcpm_port_is_disconnected(port))
18861886+ tcpm_set_state(dev, SRC_UNATTACHED, 0);
18871887+ else if (cc1 != old_cc1 || cc2 != old_cc2)
18881888+ tcpm_set_state(dev, SRC_ATTACH_WAIT, 0);
18891889+ break;
18901890+ case SRC_ATTACHED:
18911891+ case SRC_SEND_CAPABILITIES:
18921892+ case SRC_READY:
18931893+ if (tcpm_port_is_disconnected(port) ||
18941894+ !tcpm_port_is_source(port))
18951895+ tcpm_set_state(dev, SRC_UNATTACHED, 0);
18961896+ break;
18971897+ case SNK_UNATTACHED:
18981898+ if (tcpm_port_is_sink(port))
18991899+ tcpm_set_state(dev, SNK_ATTACH_WAIT, 0);
19001900+ break;
19011901+ case SNK_ATTACH_WAIT:
19021902+ if ((port->cc1 == TYPEC_CC_OPEN &&
19031903+ port->cc2 != TYPEC_CC_OPEN) ||
19041904+ (port->cc1 != TYPEC_CC_OPEN &&
19051905+ port->cc2 == TYPEC_CC_OPEN))
19061906+ new_state = SNK_DEBOUNCED;
19071907+ else if (tcpm_port_is_disconnected(port))
19081908+ new_state = SNK_UNATTACHED;
19091909+ else
19101910+ break;
19111911+ if (new_state != port->delayed_state)
19121912+ tcpm_set_state(dev, SNK_ATTACH_WAIT, 0);
19131913+ break;
19141914+ case SNK_DEBOUNCED:
19151915+ if (tcpm_port_is_disconnected(port))
19161916+ new_state = SNK_UNATTACHED;
19171917+ else if (port->vbus_present)
19181918+ new_state = tcpm_try_src(port) ? INVALID_STATE : SNK_ATTACHED;
19191919+ else
19201920+ new_state = SNK_UNATTACHED;
19211921+ if (new_state != port->delayed_state)
19221922+ tcpm_set_state(dev, SNK_DEBOUNCED, 0);
19231923+ break;
19241924+ case SNK_READY:
19251925+ if (tcpm_port_is_disconnected(port))
19261926+ tcpm_set_state(dev, unattached_state(port), 0);
19271927+ else if (!port->pd_capable &&
19281928+ (cc1 != old_cc1 || cc2 != old_cc2))
19291929+ tcpm_set_current_limit(dev,
19301930+ tcpm_get_current_limit(port),
19311931+ 5000);
19321932+ break;
19331933+19341934+ case SNK_DISCOVERY:
19351935+ /* CC line is unstable, wait for debounce */
19361936+ if (tcpm_port_is_disconnected(port))
19371937+ tcpm_set_state(dev, SNK_DISCOVERY_DEBOUNCE, 0);
19381938+ break;
19391939+ case SNK_DISCOVERY_DEBOUNCE:
19401940+ break;
19411941+19421942+ case PORT_RESET:
19431943+ case PORT_RESET_WAIT_OFF:
19441944+ /*
19451945+ * State set back to default mode once the timer completes.
19461946+ * Ignore CC changes here.
19471947+ */
19481948+ break;
19491949+ default:
19501950+ /*
19511951+ * While acting as sink and auto vbus discharge is enabled, Allow disconnect
19521952+ * to be driven by vbus disconnect.
19531953+ */
19541954+ if (tcpm_port_is_disconnected(port))
19551955+ tcpm_set_state(dev, unattached_state(port), 0);
19561956+ break;
19571957+ }
19581958+}
19591959+19601960+static void _tcpm_pd_vbus_on(struct udevice *dev)
19611961+{
19621962+ struct tcpm_port *port = dev_get_uclass_plat(dev);
19631963+19641964+ dev_dbg(dev, "TCPM: VBUS on event\n");
19651965+ port->vbus_present = true;
19661966+ /*
19671967+ * When vbus_present is true i.e. Voltage at VBUS is greater than VSAFE5V implicitly
19681968+ * states that vbus is not at VSAFE0V, hence clear the vbus_vsafe0v flag here.
19691969+ */
19701970+ port->vbus_vsafe0v = false;
19711971+19721972+ switch (port->state) {
19731973+ case SNK_TRANSITION_SINK_VBUS:
19741974+ port->explicit_contract = true;
19751975+ tcpm_set_state(dev, SNK_READY, 0);
19761976+ break;
19771977+ case SNK_DISCOVERY:
19781978+ tcpm_set_state(dev, SNK_DISCOVERY, 0);
19791979+ break;
19801980+ case SNK_DEBOUNCED:
19811981+ tcpm_set_state(dev, SNK_ATTACHED, 0);
19821982+ break;
19831983+ case SNK_HARD_RESET_WAIT_VBUS:
19841984+ tcpm_set_state(dev, SNK_HARD_RESET_SINK_ON, 0);
19851985+ break;
19861986+ case SRC_ATTACHED:
19871987+ tcpm_set_state(dev, SRC_STARTUP, 0);
19881988+ break;
19891989+ case SRC_HARD_RESET_VBUS_ON:
19901990+ tcpm_set_state(dev, SRC_STARTUP, 0);
19911991+ break;
19921992+19931993+ case PORT_RESET:
19941994+ case PORT_RESET_WAIT_OFF:
19951995+ /*
19961996+ * State set back to default mode once the timer completes.
19971997+ * Ignore vbus changes here.
19981998+ */
19991999+ break;
20002000+20012001+ default:
20022002+ break;
20032003+ }
20042004+}
20052005+20062006+static void _tcpm_pd_vbus_off(struct udevice *dev)
20072007+{
20082008+ struct tcpm_port *port = dev_get_uclass_plat(dev);
20092009+20102010+ dev_dbg(dev, "TCPM: VBUS off event\n");
20112011+ port->vbus_present = false;
20122012+ port->vbus_never_low = false;
20132013+ switch (port->state) {
20142014+ case SNK_HARD_RESET_SINK_OFF:
20152015+ tcpm_set_state(dev, SNK_HARD_RESET_WAIT_VBUS, 0);
20162016+ break;
20172017+ case HARD_RESET_SEND:
20182018+ break;
20192019+ case SNK_ATTACH_WAIT:
20202020+ tcpm_set_state(dev, SNK_UNATTACHED, 0);
20212021+ break;
20222022+20232023+ case SNK_NEGOTIATE_CAPABILITIES:
20242024+ break;
20252025+20262026+ case PORT_RESET_WAIT_OFF:
20272027+ tcpm_set_state(dev, tcpm_default_state(port), 0);
20282028+ break;
20292029+20302030+ case PORT_RESET:
20312031+ /*
20322032+ * State set back to default mode once the timer completes.
20332033+ * Ignore vbus changes here.
20342034+ */
20352035+ break;
20362036+20372037+ default:
20382038+ if (port->pwr_role == TYPEC_SINK && port->attached)
20392039+ tcpm_set_state(dev, SNK_UNATTACHED, 0);
20402040+ break;
20412041+ }
20422042+}
20432043+20442044+void tcpm_cc_change(struct udevice *dev)
20452045+{
20462046+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
20472047+ enum typec_cc_status cc1, cc2;
20482048+20492049+ tcpm_reset_event_cnt(dev);
20502050+ if (drvops->get_cc(dev, &cc1, &cc2) == 0)
20512051+ _tcpm_cc_change(dev, cc1, cc2);
20522052+}
20532053+20542054+void tcpm_vbus_change(struct udevice *dev)
20552055+{
20562056+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
20572057+ bool vbus;
20582058+20592059+ tcpm_reset_event_cnt(dev);
20602060+ vbus = drvops->get_vbus(dev);
20612061+ if (vbus)
20622062+ _tcpm_pd_vbus_on(dev);
20632063+ else
20642064+ _tcpm_pd_vbus_off(dev);
20652065+}
20662066+20672067+void tcpm_pd_hard_reset(struct udevice *dev)
20682068+{
20692069+ struct tcpm_port *port = dev_get_uclass_plat(dev);
20702070+20712071+ tcpm_reset_event_cnt(dev);
20722072+ dev_dbg(dev, "TCPM: Received hard reset\n");
20732073+20742074+ /* If a hard reset message is received during the port reset process,
20752075+ * we should ignore it, that is, do not set port->state to HARD_RESET_START.
20762076+ */
20772077+ if (port->state == PORT_RESET || port->state == PORT_RESET_WAIT_OFF)
20782078+ return;
20792079+20802080+ /*
20812081+ * If we keep receiving hard reset requests, executing the hard reset
20822082+ * must have failed. Revert to error recovery if that happens.
20832083+ */
20842084+ tcpm_set_state(dev,
20852085+ port->hard_reset_count < PD_N_HARD_RESET_COUNT ?
20862086+ HARD_RESET_START : ERROR_RECOVERY,
20872087+ 0);
20882088+}
20892089+20902090+static void tcpm_init(struct udevice *dev)
20912091+{
20922092+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
20932093+ struct tcpm_port *port = dev_get_uclass_plat(dev);
20942094+ enum typec_cc_status cc1, cc2;
20952095+20962096+ drvops->init(dev);
20972097+20982098+ tcpm_reset_port(dev);
20992099+21002100+ /*
21012101+ * XXX
21022102+ * Should possibly wait for VBUS to settle if it was enabled locally
21032103+ * since tcpm_reset_port() will disable VBUS.
21042104+ */
21052105+ port->vbus_present = drvops->get_vbus(dev);
21062106+ if (port->vbus_present)
21072107+ port->vbus_never_low = true;
21082108+21092109+ /*
21102110+ * 1. When vbus_present is true, voltage on VBUS is already at VSAFE5V.
21112111+ * So implicitly vbus_vsafe0v = false.
21122112+ *
21132113+ * 2. When vbus_present is false and TCPC does NOT support querying
21142114+ * vsafe0v status, then, it's best to assume vbus is at VSAFE0V i.e.
21152115+ * vbus_vsafe0v is true.
21162116+ *
21172117+ * 3. When vbus_present is false and TCPC does support querying vsafe0v,
21182118+ * then, query tcpc for vsafe0v status.
21192119+ */
21202120+ if (port->vbus_present)
21212121+ port->vbus_vsafe0v = false;
21222122+ else
21232123+ port->vbus_vsafe0v = true;
21242124+21252125+ tcpm_set_state(dev, tcpm_default_state(port), 0);
21262126+21272127+ if (drvops->get_cc(dev, &cc1, &cc2) == 0)
21282128+ _tcpm_cc_change(dev, cc1, cc2);
21292129+}
21302130+21312131+static int tcpm_fw_get_caps(struct udevice *dev)
21322132+{
21332133+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
21342134+ struct tcpm_port *port = dev_get_uclass_plat(dev);
21352135+ ofnode node;
21362136+ const char *cap_str;
21372137+ int ret;
21382138+ u32 mw;
21392139+21402140+ ret = drvops->get_connector_node(dev, &node);
21412141+ if (ret)
21422142+ return ret;
21432143+21442144+ cap_str = ofnode_read_string(node, "power-role");
21452145+ if (!cap_str)
21462146+ return -EINVAL;
21472147+21482148+ if (!strcmp("dual", cap_str))
21492149+ port->typec_type = TYPEC_PORT_DRP;
21502150+ else if (!strcmp("source", cap_str))
21512151+ port->typec_type = TYPEC_PORT_SRC;
21522152+ else if (!strcmp("sink", cap_str))
21532153+ port->typec_type = TYPEC_PORT_SNK;
21542154+ else
21552155+ return -EINVAL;
21562156+21572157+ port->port_type = port->typec_type;
21582158+21592159+ if (port->port_type == TYPEC_PORT_SNK)
21602160+ goto sink;
21612161+21622162+ /* Get source pdos */
21632163+ ret = ofnode_read_size(node, "source-pdos") / sizeof(u32);
21642164+ if (ret <= 0)
21652165+ return -EINVAL;
21662166+21672167+ port->nr_src_pdo = min(ret, PDO_MAX_OBJECTS);
21682168+ ret = ofnode_read_u32_array(node, "source-pdos",
21692169+ port->src_pdo, port->nr_src_pdo);
21702170+ if (ret || tcpm_validate_caps(dev, port->src_pdo, port->nr_src_pdo))
21712171+ return -EINVAL;
21722172+21732173+ if (port->port_type == TYPEC_PORT_SRC)
21742174+ return 0;
21752175+21762176+ /* Get the preferred power role for DRP */
21772177+ cap_str = ofnode_read_string(node, "try-power-role");
21782178+ if (!cap_str)
21792179+ return -EINVAL;
21802180+21812181+ if (!strcmp("sink", cap_str))
21822182+ port->typec_prefer_role = TYPEC_SINK;
21832183+ else if (!strcmp("source", cap_str))
21842184+ port->typec_prefer_role = TYPEC_SOURCE;
21852185+ else
21862186+ return -EINVAL;
21872187+21882188+ if (port->typec_prefer_role < 0)
21892189+ return -EINVAL;
21902190+sink:
21912191+ /* Get sink pdos */
21922192+ ret = ofnode_read_size(node, "sink-pdos") / sizeof(u32);
21932193+ if (ret <= 0)
21942194+ return -EINVAL;
21952195+21962196+ port->nr_snk_pdo = min(ret, PDO_MAX_OBJECTS);
21972197+ ret = ofnode_read_u32_array(node, "sink-pdos",
21982198+ port->snk_pdo, port->nr_snk_pdo);
21992199+ if (ret || tcpm_validate_caps(dev, port->snk_pdo, port->nr_snk_pdo))
22002200+ return -EINVAL;
22012201+22022202+ if (ofnode_read_u32_array(node, "op-sink-microwatt", &mw, 1))
22032203+ return -EINVAL;
22042204+ port->operating_snk_mw = mw / 1000;
22052205+22062206+ port->self_powered = ofnode_read_bool(node, "self-powered");
22072207+22082208+ return 0;
22092209+}
22102210+22112211+static int tcpm_port_init(struct udevice *dev)
22122212+{
22132213+ struct tcpm_port *port = dev_get_uclass_plat(dev);
22142214+ int err;
22152215+22162216+ err = tcpm_fw_get_caps(dev);
22172217+ if (err < 0) {
22182218+ dev_err(dev, "TCPM: please check the dts config: %d\n", err);
22192219+ return err;
22202220+ }
22212221+22222222+ port->try_role = port->typec_prefer_role;
22232223+ port->port_type = port->typec_type;
22242224+22252225+ tcpm_init(dev);
22262226+22272227+ dev_info(dev, "TCPM: init finished\n");
22282228+22292229+ return 0;
22302230+}
22312231+22322232+static void tcpm_poll_event(struct udevice *dev)
22332233+{
22342234+ const struct dm_tcpm_ops *drvops = dev_get_driver_ops(dev);
22352235+ struct tcpm_port *port = dev_get_uclass_plat(dev);
22362236+22372237+ if (!drvops->get_vbus(dev))
22382238+ return;
22392239+22402240+ while (port->poll_event_cnt < TCPM_POLL_EVENT_TIME_OUT) {
22412241+ if (!port->wait_dr_swap_message &&
22422242+ (port->state == SNK_READY || port->state == SRC_READY))
22432243+ break;
22442244+22452245+ drvops->poll_event(dev);
22462246+ port->poll_event_cnt++;
22472247+ udelay(500);
22482248+ tcpm_check_and_run_delayed_work(dev);
22492249+ }
22502250+22512251+ if (port->state != SNK_READY && port->state != SRC_READY)
22522252+ dev_warn(dev, "TCPM: exit in state %s\n",
22532253+ tcpm_states[port->state]);
22542254+22552255+ /*
22562256+ * At this time, call the callback function of the respective pd chip
22572257+ * to enter the low-power mode. In order to reduce the time spent on
22582258+ * the PD chip driver as much as possible, the tcpm framework does not
22592259+ * fully process the communication initiated by the device,so it should
22602260+ * be noted that we can disable the internal oscillator, etc., but do
22612261+ * not turn off the power of the transceiver module, otherwise the
22622262+ * self-powered Type-C device will initiate a Message(eg: self-powered
22632263+ * Type-C hub initiates a SINK capability request(PD_CTRL_GET_SINK_CAP))
22642264+ * and the pd chip cannot reply to GoodCRC, causing the self-powered Type-C
22652265+ * device to switch vbus to vSafe5v, or even turn off vbus.
22662266+ */
22672267+ if (!drvops->enter_low_power_mode)
22682268+ return;
22692269+22702270+ if (drvops->enter_low_power_mode(dev, port->attached, port->pd_capable))
22712271+ dev_err(dev, "TCPM: failed to enter low power\n");
22722272+ else
22732273+ dev_info(dev, "TCPM: PD chip enter low power mode\n");
22742274+}
22752275+22762276+int tcpm_post_probe(struct udevice *dev)
22772277+{
22782278+ int ret = tcpm_port_init(dev);
22792279+22802280+ if (ret < 0) {
22812281+ dev_err(dev, "failed to tcpm port init\n");
22822282+ return ret;
22832283+ }
22842284+22852285+ tcpm_poll_event(dev);
22862286+22872287+ return 0;
22882288+}
+1
include/dm/uclass-id.h
···139139 UCLASS_SYSCON, /* System configuration device */
140140 UCLASS_SYSINFO, /* Device information from hardware */
141141 UCLASS_SYSRESET, /* System reset device */
142142+ UCLASS_TCPM, /* TypeC port manager */
142143 UCLASS_TEE, /* Trusted Execution Environment device */
143144 UCLASS_THERMAL, /* Thermal sensor */
144145 UCLASS_TIMER, /* Timer device */