2022–02–01:
Pinephone Pro – Type C port support
Since November last year, I've been working on and off on understanding and
implementing support for Type-C port on Pinephone Pro. It's a complex physical
interface, so it was hard to understand how everything fits together on the
Rockchip platform without going through a lot of drivers and without
understanding the USB Type-C specification. I already had some grasp of the
Type-C spec from implementing support for the similar functionality on original
Pinephone.
So my approach with Pinephone Pro was to find all existing drivers that are
related to supporting all the features of the Type-C port on RK3399 and read
them top to bottom.
This gave me a nice overview of how everything can fit together eventually,
and also what's missing in mainline Linux compared to Rockchip BSP Linux.
I was also interested in making Type-C support (which includes power
negotiation, charging and supplying power, USB data role switching, Display Port
alternate mode, power delivery and BC1.2 spec support, and similar things) work
as best as possible as soon as possible, so that when Pinephone Pro got to a
wider audience, all this worked as well as was possible to achieve with my
limited resources in a few weaks before I was going to winter holidays.
Once I understood the drivers and their supposed interactions, I needed to
make them talk together with as little code changes as possible. This meant
using their existing interfaces.
Mainline Linux is moving in the direction of using in-kernel Type-C
interfaces for controlling the drivers that need to listen to the Type-C port
manager driver. Most drivers on the Rockchip platform don't support these
interfaces, and even if they did, these interfaces currently don't support
controlling multiple devices at once, which is necessary on this particular
platform. Instead, Rockchip drivers mostly use extcon
interface
(bus, really) to communicate among each other.
So as a quick stop-gap solution I decided to write the
typec-extcon
driver, which adapts Type-C mux/switch/role interfaces
into extcon ones the existing drivers understand. This made it possible to
quickly wire things things together, and be able to start testing the hardware,
and finding bugs.
It works semi-reasonably now. Interdriver communication is now solid, with my
latest kernel releases for Pinephone Pro.
That doesn't mean there are no issues. The drivers themselves, that are
already mainline, have several issues:
- fusb302 driver is not very reliable, it sometimes stops detecting all
activity on CC pins until reboot, etc. It also misdetects some host devices.
I already upstreamed one fix to a bug that was preventing the driver from
notifying change from host->peripheral mode.
- USB driver powers up phy on boot, and never shuts it down. This makes it
impossible to re-configure the type-c phy to switch superspeed signals for the
reverse orientation of the type-c plug. So things like USB-SS and DP Alt mode
work only in normal plug orientation.
- Displayport driver doesn't support higher bitrate modes. It barely supports
1080p@60 so you can't use higher resolutions on external monitor connected to
the phone.
USB driver will probably be reasonably easy to fix. BSP driver does things
correctly, so it can serve as an inspiration.
fusb302 will be tough to fix. The chip is not horribly complicated, but TCPM
driver fusb302 serves as a backend to is, and fusb302's problem is more in the
fact that it's quite low level, so you're setting comparators, dealing with
D/A converters, voltages, pull-up resistor values, etc. But the higher level
deals with abstract states on the CC pins. So far, issues with the driver
revolve around misdetection of states of CC pins, and infinite loops, or
unhandled states due to that.
Once the individual drivers are made to behave properly, it will be time to
think about mainlining this work. I have some plan that involves waiting for multi
consumer support for in-kernel Type-C interfaces, that is being proposed on
the USB mailing list to be reviewed and accepted. This patchset will help solve
the driver communication issue, in an upstreamable way, by allowing TCPM to talk
to multiple drivers at once. The drivers will also need to be adapted to use the
proper interfaces. This will be fairly easy at that point.
Once all that is done, it will be possible to upstream the whole work.
In the meantime there are drivers to fix.
Fixing up fusb302 is the highest priority. Identifying and solving issues in
the wild, from people using the interim solution will be another one.
When working on anx7688 driver I was able to stuff it with a lot of useful
debug output, that was then all printed to the kernel log. This allowed me to
just ask people to send me their dmesg output, when I noticed someone had
issues with things related to Type-C port, and I would not need much else from
them. I gradually improved the debug output as I tracked the known issues to
be able to understand them better as more people reported issues and sent the
logs. This was nice, and helped stabilize the Type-C support on original
Pinephone.
Compared to that, Pinephone Pro seems quite hopeless. There's almost
0 useful output in kernel log itself, useful logs are hidden deep in debugfs
and sysfs in several places, etc. It's very time consuming to do debugging with
users, because of that. Reading the logs is hader too, becuase they are very
verbose and low-level, and are split, so there's no single timeline to skim
through. They need to be cross-references manually.
I decided to not add to this difficulty, and only help users who will be
able to install and run my exact kernel build for debugging. It's just too much
effort to also track what subset of my patches some unknown version of the
downstream Linux distribution's kernel, with no existing git tree to diff
against, decided to include.
It will take maybe 4 kernel releases to clean up for the upstreaming
attempt.
I'll step away from this work for a while to prepare basic device tree for
Pinephone Pro and submit it mainline. Otherwise things will start getting messy
pretty soon with multiple kernel trees being actively used by distributions and
no shared base device tree upstream.