megi's PinePhone Development Log RSS

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:

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.