-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathREADME
246 lines (207 loc) · 12 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
lsucpd
======
Introduction
------------
This utility belongs to the "ls*" family of utilities found in Linux whose
names derive from the Unix ls utility (command) for listing files and
directories. In the case of lsucpd, the "ucpd" is an abbreviation for USB-C
Power Delivery (PD) which is optional on USB Type-C interconnects. A typical
USB-C interconnect consists of a power adapter (e.g. an AC 65 Watt power
adapter) and a consumer of power (e.g. a laptop). Taking those examples,
both the power adapter and the laptop will have female USB-C connectors (also
known as receptacles). A USB-C cable will complete the circuit with a male
USB-C plug on either end.
The lsucpd utility will list local USB-C ports (e.g. each female USB-C
connector on a laptop) with one line output for each local port. Those local
ports are named "port<n>" where <n> is an integer starting at 0. Although
Linux does not guarantee it, the local port numbers are observed to be stable
from one boot to the next. For those local ports connected via a cable to a
remote device there will most likely be a "port<n>-partner" which is
shortened to "partner" as the "port<n>" part would otherwise be repeated.
Not all USB-C ports support the PD protocol, but for those that do, a
"pd<n>" is shown in square brackets immediately to the right of the port
it is associated with. For example:
$ lsucpd
port0 [pd0] <<==== partner [pd4]
port1 [pd1] <<==== partner [pd5]
The direction that power is flowing is indicated by "====>>" or "<<===="
between each port<n> and its partner. Probably the most useful option
is --caps which will additionally list the source and sink capabilities of
each "pd<n>" instance.
Project Status
--------------
Can do:
- show relationship between USB Type C objects (e.g. port0 and
port1-partner) and "usb_power_delivery" objects (e.g. pd1 and pd7)
- show the source and sink capabilities of both ends of existing
PD connections
- display partner's alternate modes, if any (with -ll option)
- decode numeric PDOs and RDOs
- optionally output JSON instead of plain text
Cannot do (yet):
- show the PD contract that is active. In USB PD jargon this requires
the active RDO to be visible via sysfs
- show the actual voltage and current (and its direction) at the
time this utility is executed
The last one is aspirational and may probably require extra hardware.
This is the initial version of this utility and has only been tested on one
platform: Thinkpad X13 G3 by Lenovo. That platform relies on the UCSI
interface exposed via sysfs starting with the Linux kernel 6 series (e.g.
lk 6.4). Note that normal, non-root user privileges are sufficient to use
lsucpd.
This project should be regarded as "work-in-progress" due to its immaturity
and the kernel support could be summarized as "shaky". Often after removing
and reconnecting USB-C cables carrying power, the ucsi_acpi and typec_ucsi
modules need to be removed then re-installed on the test platform. That
does not inspire confidence.
Not known is which versions of Intel and AMD CPUs will work apart from the
one from the above laptop: Intel i5-1240P. Intel calls that "12th generation"
which was superseded this year by the 13th generation. So this utility most
likely will only work with recent laptops.
Unfortunately another company's 12th generation laptop (ASUS VivoBook
K3502ZA) loads ucsi modules, creates the typec and usb_power_delivery class
directories in sysfs, but leaves them empty. The kernel log shows a
ENOTSUPPORTED error with BIOS version 307.
Bugs, suggestions, or reports of success on other platforms can be sent to
this email address or to "Issues" at:
https://github.com/doug-gilbert/lsucpd
Like lsscsi, this utility has a --sysfsroot=SPATH option that allows it to
data-mine in another sub-tree (other than /sys ). That "other sub-tree" can
be from another machine (perhaps as a compressed tarball) and would be very
useful to the author in debugging problems. There is another utility
at github:
https://github.com/doug-gilbert/clone_pseudo_fs
designed to clone the likes of sysfs, procfs and devfs. The lsucpd utility
relies only on sysfs.
For compatibility with lsblk, lsmem and some other ls* utilities there is
also a --sysroot=AR_PT option that defaults to '/'. If AR_PT is set to /tmp
then this utility will attempt to data-mine in /tmp/sys directory.
Some background for USB PD in the Linux kernel is discussed in this post:
https://marc.info/?l=linux-usb&m=169278141600478&w=2
The next sections of this document can be safely ignored for those familiar
with USB PD and the electrical concepts that underpin it. Instructions for
building this package are in the last section.
USB-C PD details
----------------
There are two USB standards covering this area, recent versions are:
1) USB Type-C Cable and Connector Specification, Release 2.3
2) USB Power Delivery Specification, Revision 3.2, Version 1.0
- this is optional, so USB-C ports don't necessarily support PD
Both these documents are intimidating in size (424 and 1113 pages
respectively) but are freely available at usb.org in the Document library.
Both documents have extensive "Terms and Abbreviations" sections (1.5 and
1.6 respectively) that are very useful references because there are a lot
of obscure terms. For example the PD document summarizes the difference
between SOP' packet and SOP'' packet.
USB.org's use of release, revision and version defies logic. The above
standard names are taken from their front pages. Interconnects complying
with 1) do not necessarily support 2) (i.e. the PD protocol). In the absence
of PD, resistors on the CC lines determine which end is the source/host and
which end is the the sink/device. USB PD Revision 1 is history (an experiment
that failed). USB PD Revision 2 introduced fixed Vbus voltages up to 20 Volts
and with an appropriate ("Emarked") cable could carry 5 Amps for 100 Watts.
USB PD Revision 3 introduced the Programmable Power Supply (PPS) optional
capability which included current limiting (CL) by the source. Then USB PD
Revision 3.1 introduced "Extended Power Range" (EPR) with fixed voltages at
28, 36 and 48 Volts. To avoid confusion, all active PD standards prior to
Revision 3.1 were dubbed "Standard Power Range" (SPR). EPR also has a (sink)
adjustable voltage supply (AVS) range of 15 to 48 Volts _without_ current
limiting.
There are two power roles: source (power provider) and sink (power consumer).
USB-C power banks and laptops can often be both, but a single port can only
be one at a time. The USB PD term for this is "Dual Role Power" (DRP)
but most laptops, at this time, are not true DRP in the USB PD sense; they
tend to fall back to USB-A 5 Volt source/host mode when talking to a USB
memory key which is very unlikely to support USB PD. In a similar way there
are two data roles: host and device. A USB PD port that can play either role
is called "Dual Role Data" (DRD).
Some other related jargon is UFP for Upward Facing Port and DFP for
Downward Facing Port. The mental picture here is with the USB host at the
top of a hierarchy with USB devices at the bottom (i.e. the leaves) with
possibly a USB hub in the middle. So an UFP on a hub connects to a DFP on
the host (e.g. a laptop).
Electricity basics
------------------
All electrical units are metric, assuming power is not given in horsepower.
The SI unit for energy is a joule but that is a bit small as we often talk
about kiloWatt-hours, MegaWatt-hours and GigaWatt-hours. A joule is a
Watt-second (i.e. one Watt for one second) so a Watt-hour is 3,600 joules,
a kiloWatt-hour is 3,600,000 joules, etc. That naming reflects this formula:
E = P . t (1)
where E is in joules, P is in Watts and t is in seconds. [The dot is for
multiply.]
The next formula is for electrical power:
P = V . I (2)
where P is in Watts, V is in volts and I is current in Amps. The mechanical
analogy for Volts and Amps is to a pipe carrying some fluid. The voltage is
related to pressure and the current is the amount of fluid moving past a
cross-section of the pipe. Further the "fluid" in the case of electricity
is made up of electrons. Around 6.2 x 10^18 electrons is called a Coulomb
and a flow of one Coulomb per second is called an Amp.
All electrical conductors have resistance which converts part of the power
passing through them to heat. That is usually wasteful (unless it is winter).
Georg Ohm is credited with the formula that bears his name:
V = I . R (3)
where V is in Volts, I is current in Amps and R is resistance in Ohms.
Combining formula (2) and (3) by substituting V gives;
P = I^2 . R (4)
This is sometimes called the "i-squared-r" formula that even Elon Musk knows
about. Importantly it is the amount of power lost in a conductor or cable.
Resistance typically doubles when length (of a cable) doubles. Also for a
PD cable, power is lost both in the Vbus wire and the Ground wire (which
usually includes the shield). So that is two times the length of the cable.
Formula (4) tells us to reduce I as much as possible to reduce power lost
in the cable. Formula (2) tells us when we reduce I we must increase V to
maintain the same P sent across the cable. [For completeness:
superconductors have "zero" resistance, typically at cryogenic
temperatures.]
Direct Current (DC) refers to the situation where if V and I change, it
is relatively slow and not periodic. In DC circuits typically the V
(voltage) supplying power to electronics moves as little as possible.
In Alternating Current (AC) both V and I vary periodically (think
sine waves). Typically for houses incoming electrical power is at 50 or
60 Hertz AC. One Hertz is one cycle per second. Formulas (1) to (4) still
apply but become much more difficult in practice because V and I are
varying periodically.
Electric vehicles (EVs) typically have two electrical systems, a high
voltage one at 400 or 800 Volts (DC) for traction; and a low voltage
one for everything else. The low voltage electrical system has been
traditionally set at 12 Volts DC (or 6 Volts 70 years ago). Elon Musk
says that his company can save over 100 kg of copper in cables by
increasing the low voltage system from 12 to 48 Volts.
Higher voltages can be dangerous for humans. It is generally considered
that voltages above 60 Volts (DC) can be harmful. In practice (allowing
for some over-voltage situations) 48 Volts has been chosen as the highest
safe nominal voltage (DC). Both the car industry (for non-traction
purposes) and USB-C PD EPR have chosen 48 Volts DC as their highest
delivery voltage. These are for systems that humans may come in contact
with. Most laptops use around 20 Volts DC while some large MacBooks
use 28 Volts and Apple supplies a 140 Watt USB PD (EPR) charger.
Building package
================
The code can be found at: https://github.com/doug-gilbert/lsucpd
Installation instructions are in the INSTALL file.
Various options can be given to the ./configure script. Those
specific to this package are:
--enable-debug Turn on debugging
The build sequence is:
./autogen.sh ; ./configure ; make ; make install
or
./bootstrap ; ./configure ; make ; make install
Note that the final 'make install' will usually require root permissions
and will place binaries in the /usr/local/bin directory.
The code is written in C++ and assumes the features found in C++20 so
a relatively recent compiler will be required.
GNU and Clang C++ compilers forgot to add "partially" when they claimed
to support C++20. Areas of pain are the <format> and <source_location>
headers. Clang++ 14 was worse: it supported the <source_location> header
but not its functionality.
To build with g++ 12 or clang 15 the 'libfmt' library (and its header file)
may need to be installed. In Debian/Ubuntu this can be done with
'apt install libfmt-dev' .
Instruction for using cmake are in the INSTALL file.
Finally it is best to keep expectations low, especially if the
/sys/class/typec directory doesn't exist ...
Douglas Gilbert <[email protected]>
13th December 2023
lsucpd pre-release 0.92 [svn revision: 21]