https://xff.cz/git/linux/commit/?id=6c5bcb19d6e9697c44015a3727e4560bd76c2b81
2022–12–02:
Pinephone kernel news and some bits about the keyboard, too
During 6.1 Linux development cycle there were several largish changes in my
kernel, which are worth sumarizing a bit. So here you go:
sun4i-drm driver fixes
Mainline sun4i-drm diver (display driver for original Pinephone's SoC
display engine) has multiple known bugs in the DRM plane handling. I had some
workarounds for some of the issues (drm:
sun8i-ui/vi: Fix layer zpos change/atomic modesetting, drm:
sun4i-drm: Recover from occasional HW failures), but these workardounds
still didn't catch every corner case. For example during some UI app development
for my multi-boot image, I noticed that when the DRM app turns off the crtc,
when it shuts down, the driver will fail to configure the DRM plane for Linux
kernel console correctly, when Linux switches to the console later on.
So I decided to rewrite the plane z-position and update handling from
scratch, and move plane position setup to CRTC component of the DRM driver,
where it's much easier to iterate over configuration of all planes of that CRTC
and figure out what values to write to display engine's registers to make
planes display in proper z-order on the screen.
The new patches are simpler to think about, mostly delete code, and are
smaller. They are also implementing a solution to the issues that was suggested
by the driver maintainer, when some workarounds were submitted to upstream a few
years back, so they should be more upstreamable.
The new patch is drm/sun4i:
Fix layer zpos change/atomic modesetting. It needs some preparatory work in
the driver, which is split out to drm/sun4i:
Unify sun8i_*_layer structs and drm/sun4i:
Add more parameters to sunxi_engine commit callback.
sun6i-csi driver
multi-camera support rewrite
Mainline sun6i-csi driver got a lot of changes during 6.1 development cycle.
So much changes, that my multi-camera
support patch was not at all aplicable anymore.
So I ended up rewriting the patch from scratch, with focus on making as
little changes as possible. The new patch
is considerably smaller and is ready for upstreaming. I still need to update DT
binding documentation, which is also required for upstreaming.
Pinephone Pro
display fix for 60 Hz refresh rate
Pinephone Pro LCD display driver had several issues, among them the most
elusive so far was that the true refresh rate was 53 Hz instead of expected
60 Hz.
Fix proved to be somewhat similar to correcting a similar issue on original
Pinephone LCD. First, clock constraints and possibilities had to be taken into
account. RK3399 clock subsystem/PLLs can't generate arbitrary clock frequencies,
but LCD requires a precise pixel clock frequency to achieve precisely 60 Hz of
refresh rate.
If you ask the Linux clock subsystem to get you 72 MHz for the display
clock, because that's what you need, it may silently instead set up the clock
for 66.6MHz, and be all happy about it. Needless to say, this will not result in
having any precision in the refresh rate at all.
Solution to the problem is to pick some frequency we can actually get from
the clock sybsystem, and massage the „factory“ display mode settings in such
a way, so that our chosen display clock frequency would lead to 60 Hz refresh
rate. This is achieved in practice by padding or shortening the horizontal and
vertical synchronization timings.
So this is what I did a long time ago, but it resulted in one of my
Pinephone Pro's having a correct 60 Hz refresh rate, and the other to have
corrupted output to display (horizontal lines were wobbling around as if pixel
data were sometimes skipped and sometimes added during the line scan out –
but vertical synchronization was fine, and the display always show the correct
number of lines, and the lines were aligned well vertically).
I though this was some issue with display panel controller configuration,
which is done each time the display panel is powered up. I wrote a patch
to allow modifying panel mode and configuration sequence from userspace, so that
experimenting with various changes was quick and efficient, but nothing I did
affected the corruption issue.
Eventually I looked again at what could be wrong on the RK3399 SoC side, and
in particular on DSI DPHY
code and noticed that the bandwidth calculation is different in Rockchip BSP
code compared to the one used mainline. I switched the calculation to what
Rockchip uses in their kernel, which fixed the corruption issue on one of my
Pinephone Pros. This change will affect every device using the RK3399 with a
MIPI DSI panel, so I doubt it's acceptable mainline, but alternatively,
it's possible to implement direct configuration of bandwidth from device tree,
so that it doesn't need to be calculated, and can be controlled more precisely
per board DT file.
In any case, Pinephone Pro LCD driver should now be working fully and
correctly, so after some testing in the wild, it should be possible to start
mainlining work for it, too.
Pinephone keyboard power
consumption
I've noticed that my pinephone's that are connected to the keyboard are
discharging a bit more quickly than expected. It's expected for pinephone
keyboard to be constantly drainging Pinephone's main battery until it dies
(yeah, not great but that's how it is), but it should be happening at ~8 mW. So
with a fully charged battery, if Pinephone is left in the keyboard unused, it
will last for about 2 months,… maybe slightly less.
The keyboard seems to be discharging the phone in a few weeks, though. So
I've cut up the keyboard, so that I can measure the power consumption of the
keyboard part of the circuit…
… and it seems to consume:
- when the phone is off: ~8mW when no key is pressed and ~20mW when some key
is pressed
- when the phone is on: ~8mW before the first key is pressed and ~20mW forever
after, even after powering off the phone
So the kernel driver does something to the keyboard firmware that makes it
permanently consume 20mW and not go into low power mode, after the first
key press.
Something for a TODO, to improve in the future. :) For now, it's best to
remove the phone from the keyboard if you're not be using the phone for more
than a few days, otherwise the keyboard will needlessly dicharge the
phone's battery in about 3 weeks.
According to keyboard MCU datasheet, power consumption of <1mW should be
possible in power down mode. But I was not able to achieve it last year, when
writing the original firmware. That may be something to revisit when looking at
the above bug, too, now that I've cut up the keyboard again anyway.
Pinephone keyboard power
manager
I have integrated my power
manager for the pinephone keyboard into my kernel and changed it a bit
compared to where it was early in the year. Early this year, I thought I can
use the capacity reported by the phone and by the keyboard driver to drive the
algorithm behind this driver, but values reported by these power supply drivers
are wildly inaccurate and tend to vary/jump around a lot, especially in response
to control actions performed by the power management driver. Reported capacity
is also wildly inaccurate. In this new version of the driver, I stopped relying
on driver reported capacity of batteries, and switched to relying on battery
voltage. All the driver needs for control purposes is „is the battery almost
dis/charged?“ and using battery voltage to determine that is much more robust
than some „capacity“ value dreamed up by the drivers. To avoid control loop
oscillations, the driver now uses timers to keep some decision for a reasonable
length of time, during which voltage changes are ignored.
Anyway, this driver manages charging cycle of both batteries so that the
energy is used more wisely and provides LED triggers, uevents and combined
cached state of the whole keyboard/phone combo in
debugfs/kbpwr/state
which is usable for summary capacity/discharge
rate reporting in userspace. This is non-standard interface, so it will only
work if you write some scripts for getting the values out of there. Standard
userspace can still see individual batteries and display combined capacity for
them somehow. For that purpose I've also added reporting of design total energy
of the batteries to sysfs, so that userspace programs can better report combined
remaining state of charge by taking into account that the batteries have
different „sizes“. :)
The driver optimizes for the highest power efficiency. Power is used more
directly without needless recharging of phone's battery from the keyboard
battery.
The driver also performs calibration of kb battery internal resistance to
improve reliability of capacity reporting of keyboard battery. Current value of
internal resistance of the battery is critically important to guess the open
circuit voltage (OCV, voltage when the battery is not under load) of the
battery, which is used to lookup the battery's remaining capacity from a
OCV->capacity lookup table.
The driver optionally provides emergency shutdown when both batteries are
almost discharged.
You can enable and disable the driver's control loop via sysfs
like this:
echo 1 > /sys/devices/platform/keyboard-power/disabled
The driver is still a bit experimental (it has verbose debugging enabled, and
lacks testing in some corner case situations), and will probably be disabled by
default in my final release of my Linux 6.1 branch.
Lots of other smaller things
My Linux 6.1 branch now uses latest mainline keyboard driver from Samuel Holland. I added some patches on
top, to be able to experiment with various xkb settings in userspace. In
particular, it's possible to disable the keyboard part of the driver, and also
the Fn overlay layer (and implement it in userspace instead). All these changes
can be seen in ppkb-6.1 branch.
There was also an issue with power key interrupt handling code on original
Pinephone reported in pinephone chat, where if you released power key while the
kernel was still resuming from sleep, the power key would get stuck in pressed
state, possibly causing some issues to userspace, which is now fixed.
I've also split device tree for pinephone 1.2 and pinephone 1.2b, because
I've not found other way to make magnetometer work on both of these Pinephone
variants. This will likely not work great for distributions using U-Boot and
U-Boot based Pinephone variant autodetection, which is only capable of
determining Braveheart from other Pinephone variants. Detecting what
magnetometer is used and selecting what 1.2 DT variant to use should be
possible though. But it will require some U-Boot patches.
I've tried to make some of my internal tooling to work with the new
magnetometer used in Pinephone 1.2b and noticed that buffered capture is not
implemented in af8133j driver, so I've added
support for that, too.
Overall 6.1 is looking out to be a very nice kernel release for Pinephone
and Pinephone keyboard.