Skip to content

RK3326: add GKD Pixel 2 (subdevice c) support#2993

Open
Jacob-Matthew-Cook wants to merge 10 commits into
ROCKNIX:nextfrom
Jacob-Matthew-Cook:gkd-pixel2-support
Open

RK3326: add GKD Pixel 2 (subdevice c) support#2993
Jacob-Matthew-Cook wants to merge 10 commits into
ROCKNIX:nextfrom
Jacob-Matthew-Cook:gkd-pixel2-support

Conversation

@Jacob-Matthew-Cook

@Jacob-Matthew-Cook Jacob-Matthew-Cook commented Jul 7, 2026

Copy link
Copy Markdown

Summary

  • Adds full boot/display/input support for the GKD Pixel 2 handheld (RK3326S), merged into RK3326 subdevice b.
  • PX30S SoC-variant kernel patches: ports the official Rockchip vendor commits for this silicon variant (TSADC, OTP, GPU power-domain, DSI DPHY timing, USB2 PHY tuning, io-domain) onto a shared soc_is_px30s() detection helper ported from the vendor's own cpuinfo infrastructure.
  • Black-screen root cause and fix: the panel is a genuine Sitronix ST7701-family part, mislabeled sitronix,st7703 in the vendor tree. Its DSI reset-gpios polarity was also wrong (active-low instead of active-high), so the panel was being told to exit reset every boot and instead held in it the whole time - it never processed a single DSI command, which is why the backlight came on but the screen stayed black. Adds a proper gkd,pixel2-panel entry to mainline's panel-sitronix-st7701.c with correct reset/enable GPIO sequencing for this IC family.
  • Input: EmulationStation (es_input.cfg) and RetroArch autoconfig entries (previously missing entirely for this board), an A/B button swap fix, and GPIO battery-status LED support (4 green + 1 yellow, percentage-tiered).
  • Bootloader: simplified to ROCKNIX's own self-contained SPL+BL31+trust+U-Boot blob (dropped an earlier vendor-idbloader hybrid once this blob was confirmed to correctly train the board's LPDDR4 RAM).
  • USB OTG host-mode detection, backlight minimum-brightness floor correction.

Testing

  • Built and tested on real GKD Pixel 2 hardware.
  • Confirmed working: boot, display (correct orientation, no PX30S-specific artifacts), touch/button input (D-pad, face buttons, shoulders/triggers, select/start/menu), battery status LEDs, USB OTG host mode.
  • Known open issues, not yet resolved:
    • Rumble motor stays disabled: the PWM channel powers up already-enabled/inverted/duty==period, which an active-low motor driver reads as permanently "on". Confirmed via force-feedback testing that it can be stopped once forced into a real driver-verified state - only the very first transition away from the exact boot-inherited register state fails. Two fixes tried and disproven on hardware so far (PWM core stale-state strobe, missing PWM_LOCK_EN hold time).
    • Sleep/wake: device suspends correctly but does not wake at all. A dev_pm_set_wake_irq() fix for the power button was tried and tested with no change, so that isn't the (or the only) root cause; a suspend-mode quirk workaround was also attempted without success.

Additional Context

  • The two open issues above (rumble, sleep/wake) are the main areas where review/testing help would be valuable - both are hardware-state-dependent and have resisted the fixes tried so far.
  • GPU (Mali/libmali) rendering has not been independently verified beyond the display pipeline working - worth confirming under real 3D workloads.

AI Usage

Did you use AI tools to help write this code? YES

@stolen

stolen commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

This looks like too large modification for supporting just one device.
Hard to verify where LLM does something useful and where just doesn't try specify needed stuff in dts.

@stolen

stolen commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Kernel patches look like they are implemented by LLM.
Meanwhile BSP kernel 6.1 has its own px30s patches
https://github.com/rockchip-linux/kernel

~/px30s/kernel$ git l1 | grep -Ei '(px30s|rk3326s)'
| * | | | | | ac35846c24ff Zhihuan He   arm64: dts: rockchip: px30s: reduce LP4 overshoot when ODT off
| * | | | | | b6de31a02254 Guochun Hu.. phy/rockchip: inno-dsidphy: add support px30s
| * | | | | | 480163a87a56 Zhen Chen    soc: rockchip: power-domain: correct name of pd_gpu for px30s
| * | | | | | 28bf3a52e49f Jianqun Xu   arm64: dts: rockchip: px30 set io drive-strength-s for px30s
| * | | | | | 711167d7b0b2 Jianwei Zh.. phy: rockchip: inno-usb2: support rk3326s and px30s tuning
| * | | | | | 41f9bdf3cf40 Liang Chen   soc: rockchip: power-domain: keep pd_gpu always on for px30s
| * | | | | | 0a724e69ebb3 Zefa Chen    phy: rockchip: mipi-rx: support rk3326s mipi dphy rx
| * | | | | | 779017748410 Jianqun Xu   power/avs: rockchip-io-domain: px30s not support pmuio1 1v8 mode
| * | | | | | 3724dcef5f0c Elaine Zhang clk: rockchip: px30: support px30s
| * | | | | | f4d06e8002ea Elaine Zhang arm64: dts: rockchip: px30s: add scmi/opp-table/dmc_fsp node
| * | | | | | | | | | bc7c0c8e19f4 Finley Xiao  thermal: rockchip: Support the px30s SoC in thermal driver
| * | | | | | | | | | c106a565f611 Jianqun Xu   pinctrl: rockchip: fix drive strength set for rk3308bs/px30s/rk3326s
| * | | | | | | | | | fd7fa23ef959 Finley Xiao  nvmem: rockchip-otp: Add support for px30s otp
| * | | | | | | | | | 84d26633c7a4 Liang Chen   soc: rockchip: add cpuid for px30/px30s

Why not port these patches to mainline?

@Jacob-Matthew-Cook

Copy link
Copy Markdown
Author

I'll can trim down and remove the unnecessary source edits, as well as any excess patch files. I have been referencing the px30s source code from the BSP 6.1 when making these edits, but we can definitely import these driver files outright. That is a better idea.

@AveyondFly

AveyondFly commented Jul 9, 2026

Copy link
Copy Markdown

I'll can trim down and remove the unnecessary source edits, as well as any excess patch files. I have been referencing the px30s source code from the BSP 6.1 when making these edits, but we can definitely import these driver files outright. That is a better idea.

Hi, in fact I also spent some time on RK3326s before with another device GameMT E6. In my fork, I can boot the 3326s device with bsp 6.6 kernel. And the basic funcionality works properly. The only leftover is after suspend, the device will not recognize the USB port and something wrong with devfreq.
I assume LLM just need to do the adaption for dts in my fork. I have add the RK3326S device.
https://github.com/AveyondFly/distribution_rocknix

update:
Switch to 5.10 BSP and add pxiel2 with cursor's composer2.5's help:
https://github.com/AveyondFly/distribution-nightly/releases/download/nightly-20260713/AURKNIX-RK3326S.aarch64-20260713.img.gz

@Jacob-Matthew-Cook

Copy link
Copy Markdown
Author

If I am not mistaken, wouldn't the ROCKNIX dev's want the ROCKNIX kernel to be built and compatible with this device? Many other distributions (ROGUE OS, Knulli) leverage the BSP Kernel. While this is fine, I am not sure this is satisfactory for mainline ROCKNIX. The problems we are having stem directly from porting to the ROCKNIX kernel.

I can definitely look at your code as a reference and use it to help make an "RK3326S" device in the devices list.

@Jacob-Matthew-Cook

Copy link
Copy Markdown
Author

@stolen With the help of r3claimer we have the screen working, and have confirmed the Audio, USB, and Buttons are all working. I have also attempted to minimize any excess modification to the ROCKNIX source tree, and have imported the necessary PX30S patches from their BSP tree.

@r3claimer

r3claimer commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Here is the logic to add LED controlls to the dts. Luckily they are just basic GPIO.

leds {
	compatible = "gpio-leds";
	pinctrl-names = "default";
	pinctrl-0 = <&led_gpio>;

	led-0 {
		gpios = <&gpio1 RK_PB2 GPIO_ACTIVE_HIGH>;
		label = "battery0";
	};
	led-1 {
		gpios = <&gpio1 RK_PB4 GPIO_ACTIVE_HIGH>;
		label = "battery1";
	};
	led-2 {
		gpios = <&gpio1 RK_PB5 GPIO_ACTIVE_HIGH>;
		label = "battery2";
	};
	led-3 {
		gpios = <&gpio1 RK_PB6 GPIO_ACTIVE_HIGH>;
		label = "battery3";
	};
	led-4 {
		gpios = <&gpio1 RK_PB7 GPIO_ACTIVE_HIGH>;
		label = "battery4";
	};
};

&pinctrl {
	led {
		led_gpio: led-gpio {
			rockchip,pins =
				<1 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>,
				<1 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>,
				<1 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>,
				<1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>,
				<1 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
		};
	};
};

I believe they will show in /sys/class/leds/brightnessX. Just adding to the dts turns them all on by default. Echo just a 0 or a 1 should turn them on and off. Ideal would be to create a script that showed the remaining battery percentage relflect in number of leds lit up.

@Jacob-Matthew-Cook

Copy link
Copy Markdown
Author

We have enabled GPIO LED control for the GKD Pixel2. Added a gpio-leds node for the five battery-indicator LEDs (gpio1 RK_PB2/PB4/PB5/PB6/PB7), based on the GPIO wiring @r3claimer posted above. They're exposed under /sys/class/leds/batteryN/brightness.

@Jacob-Matthew-Cook

Copy link
Copy Markdown
Author

Important: resume-from-sleep is still NOT working correctly on the GKD Pixel2. The device suspends fine but does not wake.

Investigation update: found the likely root cause via the vendor rockchip-linux/kernel tree - on PX30S, the deepest suspend modes are governed by ATF/BL31 firmware, not Linux. device_init_wakeup()/enable_irq_wake() only keep an IRQ line unmasked; firmware alone decides what wakes the CPU cores once they're powered off. Our board's devicetree already carries the correct rockchip,sleep-mode-config/rockchip,wakeup-config values (copied from the vendor tree), but nothing in this kernel ever parsed the rockchip,pm-px30 compatible string or sent those values to firmware.

Added 034-px30s-suspend-wakeup-config.patch, a trimmed port of the vendor's rockchip_pm_config.c that sends this config via the SIP_SUSPEND_MODE SMC call. It compiles cleanly against this kernel/config, but has not been confirmed working on real hardware - it depends on this board's BL31 firmware blob actually implementing that SIP call. If it doesn't, this is a silent no-op and wake-from-sleep remains broken. Needs real-hardware testing before this can be considered resolved.

@Jacob-Matthew-Cook

Copy link
Copy Markdown
Author

Ready for alpha testing.

Summary of where things stand:

  • Display, audio, USB, buttons (A/B swap fixed), battery LED control, and FUNC-key hotkey are all working and confirmed on real hardware.
  • Battery/fuel-gauge reporting confirmed accurate after a one-time PMIC recalibration (documented, not yet automated as a quirk).
  • Input controls now wired up beyond RetroArch: gamecontrollerdb.txt (covers most standalone emulators/apps generically) plus explicit Flycast/Mupen64Plus configs for the two that need per-device sections.
  • Fixed a real bug in the shared RK3326 update.sh bootloader script: subdevice detection never resolved to "c", so a .tar/.img update would have flashed the wrong u-boot binary onto this board. Fixed with proper Pixel2 detection.
  • Known open issue: wake-from-sleep does not work. Two separate fix attempts (a kernel wake-irq patch, and a ported vendor SIP suspend-mode driver - confirmed this board's BL31 does implement the required SIP call) were both tested on real hardware with no change in behavior. Root cause still open. A temporary freeze (s2idle) workaround is in place so sleep/resume is at least usable in the meantime.

@stolen @r3claimer - given the volume of changes, would appreciate eyes on this whenever you have a chance, especially the wake-from-sleep investigation if either of you has PX30S/ATF firmware insight.

@Jacob-Matthew-Cook

Copy link
Copy Markdown
Author

GKD Pixel2 is now merged into Device B — subdevice "c" has been removed entirely.

Its u-boot/kernel/system payload was already identical to subdevice b's, so the only real difference was dtb selection. Since Pixel2 has no analog stick wired to the SARADC channel the existing ADC-hwid mechanism relies on (that pin floats and can land in any board's range on a given boot), b_boot.ini now detects it directly from the SoC's own silicon instead: PX30S vs plain PX30 differ in the DDR_GRF_CON1 register (bits 15:14 read 0b11 only on PX30S), checked before and taking priority over the ADC-based selection every other subdevice-b board uses.

Verified working on real hardware.

@Jacob-Matthew-Cook

Copy link
Copy Markdown
Author

Alpha 1.0 - feature complete. 🎉

GKD Pixel2 support has since been merged into subdevice b (no longer a separate subdevice c) with hardware-silicon-register-based DTB selection, so it coexists cleanly with the other RK3326 "b" boards without any impact on them.

Working: display, audio, RTL8188EUS WiFi dongle, USB peripherals (keyboard/storage etc. via the OTG port - now correctly powers what's plugged in), all buttons (A/B swap fixed), battery status LEDs, battery/fuel-gauge reporting, standalone-emulator input controls across all bundled apps.

Last remaining TO-DO: wake-from-sleep still doesn't work correctly - proper suspend-to-memory needs further investigation. A temporary freeze (s2idle) workaround is included so sleep/resume is at least usable in the meantime. This is the only thing standing between this and calling it fully complete.

Release with SD card image + update tar: https://github.com/Jacob-Matthew-Cook/distribution/releases/tag/pixel2-alpha-1.0

@Jacob-Matthew-Cook

Copy link
Copy Markdown
Author

Update: fixed a regression introduced by the USB vbus-supply fix from the previous update — the port was always self-powering in host mode and never auto-negotiating charging/device mode when plugged into a charger or PC (only manually forcing gadget mode worked).

Root cause: the shared RK3326 usb-role-switch default ("host", from 022-usb-role-switch.patch) had been harmless on every other RK3326 board since none of them wire vbus-supply - defaulting to host never actually drove VBUS. Once we wired it for peripheral power, "default host" became electrically real for the first time, permanently self-sourcing 5V and starving dwc2's ID/VBUS-valid detection of a clean transition to notice. The vendor kernel never sets a default role at all here, relying purely on hardware ID/VBUS detection - dropped the forced default for this board only (shared patch and every other RK3326 board untouched).

Release assets updated in place: https://github.com/Jacob-Matthew-Cook/distribution/releases/tag/pixel2-alpha-1.0

@Jacob-Matthew-Cook

Copy link
Copy Markdown
Author

Wrapping up this development pass — Alpha 1.1 to follow.

We're done with our current round of work on the Pixel2 and would like to get this merged before starting on more complex features, so that work can build on a merged baseline rather than an ever-growing fork branch.

Since the last update, we've added:

  • More robust panel dimming: on many units, the display would turn off entirely if brightness was set to the minimum, since the panel can't sustain visible output below a certain PWM duty cycle. The brightness floor has been raised accordingly, to ~17/255 instead of ~12/255.
  • A more robust battery/power LED display: solid red below 10%, and 1/2/3/4 solid green LEDs for the 25/50/75/100% tiers respectively, plus a distinct charging pattern.
  • The LEDs now flash all together to signal when the device is stuck in USB "Host" mode following insertion of a peripheral - this is the state where the port self-sources 5V and can't sense external power, so this gives a clear visual indicator (and prompts the user to reset the device) instead of silently failing to charge.

Known "nice to haves" for follow-up work (not blocking this merge):

  1. More robust USB-OTG state transitions - the port can currently get stuck in either a "Host" or "Peripheral" configuration depending on whether a dongle or a wall charger was plugged in most recently, requiring a device reset to recover.
  2. Fix PWM motor (rumble) initialization - if enabled in the devicetree, the motor is always on until the driver later activates/deactivates it at some point; root cause still open despite several fix attempts.
  3. Properly configure Suspend-to-Memory sleep mode - freeze (s2idle) remains the working interim mode in the meantime.

Let us know if there's anything else needed before merge.

@Jacob-Matthew-Cook
Jacob-Matthew-Cook force-pushed the gkd-pixel2-support branch 2 times, most recently from 6b80a7a to 6fee235 Compare July 13, 2026 21:47
@Jacob-Matthew-Cook

Jacob-Matthew-Cook commented Jul 13, 2026

Copy link
Copy Markdown
Author

Update on the rumble motor: the long-standing "always on from boot" issue is partially fixed.

Root cause found via live-hardware register testing: the vendor-extracted rk3326s-gkd-pixel2.dtsi uses normal PWM polarity for the vibrator channel, but this board's dts used inverted polarity - chosen originally to match the channel's already-stuck-on boot state, which was backwards (that boot state was the bug, not the intended spec). Matching the vendor's real polarity was necessary but not sufficient on its own.

The remaining piece is fixed with a small rocknix-joypad patch that forces a genuine mid-duty "kick" at probe time before disabling the channel - this reliably clears the stuck-on-boot state on real hardware.

EDIT: I have properly fixed it. For some reason on the Pixel2, pwm0 was in the joypad, when it is supposed to be managed by pwm-vibra. I still need a patch at boot to initialize the pwm0 on the Pixel2 to off, but by using this module, we have made it appear almost immediately in the boot process.

@Jacob-Matthew-Cook

Copy link
Copy Markdown
Author

Alpha 1.2 - PWM rumble mostly resolved.

Following up on the rumble motor issue: it's now fixed via a small kernel patch (030-pwm-vibra-kick-stuck-boot-state.patch) rather than anything in the joypad driver. Root cause was twofold:

  1. The channel was wired through rocknix-singleadc-joypad's own rumble handling, an out-of-tree loadable kernel module that doesn't probe until ~10s into boot. Moved it to the mainline pwm-vibrator driver instead (already built into the kernel image, and already used by sibling RK3326 boards like rg351m/rg351v), which probes during early kernel init (~0.65s, matching stock firmware).
  2. That alone wasn't sufficient: the channel can power up already latched in a stuck-on state that a plain disable never clears. The new kernel patch kicks it at probe time - ramping duty from 90% down to 0% over 250ms before disabling - forcing the first real hardware transition automatically, before userspace ever sees the device. Scoped to soc_is_px30s() so it only affects this silicon variant; every other board sharing this driver keeps the original, unmodified behavior.

Uploading this now as Alpha 1.2.

Remaining known issues:

  1. Suspend-to-memory sleep still doesn't wake correctly - freeze (s2idle) remains the working interim mode.
  2. USB-OTG state transitions aren't fully robust - the port can get stuck in either a "Host" or "Peripheral" configuration depending on what was plugged in most recently, requiring a device reset to recover.

This is intended to be the last major Alpha release before this gets merged into mainline - further fixes for the two items above would ideally happen post-merge rather than continuing to grow this branch further.

@AveyondFly

Copy link
Copy Markdown

Alpha 1.2 - PWM rumble mostly resolved.

Following up on the rumble motor issue: it's now fixed via a small kernel patch (030-pwm-vibra-kick-stuck-boot-state.patch) rather than anything in the joypad driver. Root cause was twofold:

1. The channel was wired through `rocknix-singleadc-joypad`'s own rumble handling, an out-of-tree loadable kernel module that doesn't probe until ~10s into boot. Moved it to the mainline `pwm-vibrator` driver instead (already built into the kernel image, and already used by sibling RK3326 boards like `rg351m`/`rg351v`), which probes during early kernel init (~0.65s, matching stock firmware).

2. That alone wasn't sufficient: the channel can power up already latched in a stuck-on state that a plain disable never clears. The new kernel patch kicks it at probe time - ramping duty from 90% down to 0% over 250ms before disabling - forcing the first real hardware transition automatically, before userspace ever sees the device. Scoped to `soc_is_px30s()` so it only affects this silicon variant; every other board sharing this driver keeps the original, unmodified behavior.

Uploading this now as Alpha 1.2.

Remaining known issues:

1. Suspend-to-memory sleep still doesn't wake correctly - `freeze` (s2idle) remains the working interim mode.

2. USB-OTG state transitions aren't fully robust - the port can get stuck in either a "Host" or "Peripheral" configuration depending on what was plugged in most recently, requiring a device reset to recover.

This is intended to be the last major Alpha release before this gets merged into mainline - further fixes for the two items above would ideally happen post-merge rather than continuing to grow this branch further.

Great work! Some comments.

Regarding the vibration, I assume just adding things like that pwm and set pwm0 as okay should be fine. Nothing special is needed. At least from my 5.10 port which uses the same driver.

My LLVM also added a special patch for otg switch, maybe as reference.

And spleep suspend usually strong related to u-boot.

@Jacob-Matthew-Cook

Copy link
Copy Markdown
Author

Wake-from-sleep is fixed. Root cause: the earlier suspend-mode-config port only forwarded rockchip,sleep-mode-config/wakeup-config once, at probe time. The vendor driver also sends LINUX_PM_STATE (which suspend state Linux is actually entering) via the same SIP call on every suspend attempt, from a dev_pm_ops.prepare hook - that call was missing entirely from the earlier port. Added it (031-px30s-suspend-wakeup-config.patch), and the device now wakes correctly from "mem" suspend. Confirmed on real hardware.

New follow-up issue found in the process: the system crashes a few seconds after waking. Investigating separately - will update here once resolved.

@Jacob-Matthew-Cook

Copy link
Copy Markdown
Author

Quick update: found and fixed a real bug where the GKD Pixel2 (PX30S) was running its CPU/GPU on generic PX30 voltage tables, overvolting the silicon at every frequency step. Corrected OPP tables are in now, with vendor's full frequency range and a safety margin validated on hardware.

Still actively working on getting resume-from-suspend fully stable - wakes correctly now, but a hang a few seconds after resume remains under investigation.

Adds a mainline/ROCKNIX-style board port for the GameKiddy GKD Pixel2
(RK3326S/PX30S), reconstructed from the vendor-extracted devicetree on
top of the shared rk3326.dtsi, alongside the U-Boot and kernel-side
fixes needed for it to work reliably:

- Rumble via the mainline pwm-vibrator driver, with a fully-charged
  LED state and fixes for a stuck-on-boot PWM state.
- PX30S-specific fixes ported from the vendor BSP kernel: the OTP
  active/standby read protocol (mainline otherwise always uses the
  wrong, plain-PX30 read path), and CPU/GPU wake/suspend-mode SIP
  configuration for firmware-controlled deep suspend states.
- A GPU clock double-management bug between genpd's automatic
  GENPD_FLAG_PM_CLK tracking and mali_kbase's own direct clock
  management, confirmed via live dmesg to cause "Enabling unprepared
  clk_gpu" / -ESHUTDOWN during real resume - genpd no longer tracks
  the GPU domain's clock on PX30S, leaving mali_kbase as sole owner.
- Board-local CPU/GPU OPP tables using this board's own real,
  vendor-validated voltages (confirmed against the vendor's own
  decompiled devicetree, since this board's real firmware uses the
  generic PX30 tables rather than the lower-voltage PX30S-suffixed
  ones some other porting attempts assume), fixing both a CPU
  overclock freeze and contributing to the deep-suspend/resume
  reliability fix above.

With these fixes, deep suspend/resume (not just s2idle) now works
consistently on real hardware, so the earlier freeze-as-default-
suspend-mode workaround for this board is removed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Jacob-Matthew-Cook

Copy link
Copy Markdown
Author

Alpha 1.3 (Final) is complete - proper suspend-to-memory now working

Deep suspend/resume (real mem sleep, not just freeze/s2idle) now works consistently on real hardware. Root cause was two compounding bugs, both fixed:

  1. A GPU clock double-management bug between genpd's automatic clock tracking and the mali_kbase driver's own direct clock management, confirmed via live dmesg to cause "Enabling unprepared clk_gpu" / -ESHUTDOWN during real resume.
  2. Incorrect CPU/GPU OPP table voltages - this board's real vendor firmware uses the generic PX30 voltage tables, not the lower-voltage PX30S-suffixed ones an earlier port assumed, which was silently undervolting the CPU/GPU at their higher operating points.

The freeze-as-default-suspend-mode workaround has been removed now that deep suspend is reliable.

The only remaining known issue is out of scope for this PR: USB-OTG state transitions aren't fully robust - the port can get stuck in either a "Host" or "Peripheral" configuration depending on what was plugged in most recently, requiring a device reset to recover. Left for follow-up work post-merge.

Alpha 1.3 build artifacts (flashable image + update tar, with checksums): https://github.com/Jacob-Matthew-Cook/distribution/releases/tag/pixel2-alpha-1.3

@labac-dev

Copy link
Copy Markdown

@Jacob-Matthew-Cook I tested the Alpha 1.3 build on real hardware. The first boot was completely normal. However, after changing the language and timezone in the Settings and performing a restart, the device gets stuck on a black screen (the backlight is on, but there is no display) right after the boot logo.

Jacob-Matthew-Cook and others added 5 commits July 15, 2026 11:16
rk3326s-gkd-pixel2-system.dtsi is U-Boot's SPL-stage devicetree
(u-boot,dm-pre-reloc/dm-spl markers, generic rockchip,rk3326-evb
compatible) from the initial port commit - never #include'd by
anything that actually builds, same as the other reference-only
.dtsi files already kept around for vendor comparison. Has no CPU/GPU
OPP tables or anything else relevant to the ongoing suspend/OPP work,
since SPL doesn't do frequency scaling at all.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…via Kconfig

Simplifies two board-specific U-Boot patches into plain defconfig
changes:

- CONFIG_ROCKCHIP_OTP=y removed. rockchip_cpuid_from_efuse() is
  entirely gated on CONFIG_ROCKCHIP_EFUSE || CONFIG_ROCKCHIP_OTP
  (neither is otherwise set on this board), so dropping it removes
  0002-px30s-otp-read-protocol.patch's need to exist. Accepted
  tradeoff: cpuid# is no longer read from hardware at all, so
  rockchip_setup_macaddr()'s SHA256-derived ethaddr/eth1addr are now
  based on whatever was on the stack at that point rather than real
  OTP data - likely identical across every unit of this board, not a
  correctness regression from before OTP worked, but not a real
  per-device MAC either.

- CONFIG_ROCKCHIP_BOOT_MODE_REG=0x0 added, replacing
  0003-disable-adc-download-key-false-trigger.patch. boot_mode.c
  compiles rockchip_dnl_key_pressed() (the ADC-based download-key
  check that misfires on this board, since it has no analog stick and
  the floating SARADC channel reads as "key pressed") entirely out
  under `#if (CONFIG_ROCKCHIP_BOOT_MODE_REG == 0)`. Accepted tradeoff:
  fastboot_set_reboot_flag() (CONFIG_FASTBOOT=y is enabled) writes
  directly to CONFIG_ROCKCHIP_BOOT_MODE_REG outside that same guard,
  so `reboot fastboot` now writes to physical address 0x0 instead of
  the real boot-mode flag register - reboot-to-fastboot is not
  expected to work correctly as a result.

Verified via a full u-boot package rebuild: CONFIG_ROCKCHIP_OTP absent
and CONFIG_ROCKCHIP_BOOT_MODE_REG=0x0 present in the resulting .config,
only 0001-add-support-for-k36-clone-with-emmc-rk3326.patch left
applied, and the build completes end-to-end.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…iver

The panel now uses the rocknix,generic-dsi driver (already used by
other RK3326 boards, e.g. rk3326-gameconsole-eeclone.dts) with an init
sequence reconstructed for this panel, rather than the previous
gkd,pixel2-panel/st7701 driver approach. Confirmed working on real
hardware with reset-gpios set to GPIO_ACTIVE_LOW, matching the
vendor-extracted rk3326s-gkd-pixel2.dtsi (the committed dts previously
had this set to GPIO_ACTIVE_HIGH, which left the screen blank).
vdd-supply/iovcc-supply replace VCC-supply/IOVCC-supply to match this
driver's actual regulator binding names.

029-gkd-pixel2-st7701-panel.patch is removed - nothing references
"gkd,pixel2-panel" anymore, so it's dead code.

Also two small cleanups noticed along the way:
- update.sh: removed a redundant PX30S devmem register check that only
  produced a log line and never affected SUBDEVICE selection - the
  kernel-side soc_is_px30s() detection already covers this.
- b_boot.ini: flattened the DTB-selection logic from a nested if into
  a single if-elif-elif-elif-else chain, matching the style already
  used elsewhere in this file.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Deep ("mem") suspend/resume itself now works correctly - the earlier
"never wakes" issue this quirk was written for is fixed. But real
hardware testing this session found a separate, still-unresolved bug:
if a dynamic CPU governor (schedutil/ondemand) is active after resume,
the system reliably crashes within seconds (confirmed memory
corruption - a real page-table translation fault), needing both a CPU
frequency/voltage transition and concurrent memory-management activity
to manifest. Static governors never trigger it, and a fresh boot
survives arbitrarily many/fast transitions under identical load - only
post-resume is affected.

Extensive investigation (kernel-side regulator/clk/OPP theories, BL31
firmware reverse engineering, and two real-hardware attempts at
triggering PX30S's DDR PHY calibration path directly - both of which
caused a full device reset instead of fixing anything) found no root
cause. Until one is, default to "freeze" (s2idle) instead of deep
suspend: CPU cores stay mostly on and idle rather than powering off and
later resuming DVFS, sidestepping the corruption path entirely rather
than fixing it. Same mechanism RK3576 uses for the same class of issue.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Same category as the already-removed rk3326s-gkd-pixel2-system.dtsi:
a vendor-extracted reference devicetree (model = "GameKiddy GKD Pixel2
Uboot") kept for provenance/comparison during this board's bring-up,
never #include'd or otherwise referenced by anything that actually
builds.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Jacob-Matthew-Cook

Copy link
Copy Markdown
Author

@Jacob-Matthew-Cook I tested the Alpha 1.3 build on real hardware. The first boot was completely normal. However, after changing the language and timezone in the Settings and performing a restart, the device gets stuck on a black screen (the backlight is on, but there is no display) right after the boot logo.

You're right, I am noticing sometimes that the screen does this sometimes after restarting. Thanks for testing. I am not sure if this is some issue with the panel timing or the device internals not fully resetting and being in a weird state (the latter is my current theory). I have also updated the Alpha with our findings today that deep suspend does not work completely, and have since readded the necessary quirk file for freeze to be the default.

If your screen is completely black, fully power cycle the device, or suspend-then-resume. It is not the most elegant solution, but we will want to troubleshoot the display drivers a bit more as well. @stolen I think this branch is ready for merge into nightly, if you're up for it?

Jacob Cook and others added 3 commits July 16, 2026 12:46
rk3326s-gkd-pixel2.dtsi is the vendor-extracted, decompiled-from-stock-
firmware reference tree - only ever referenced in prose comments on
the actual board dts, never #included or otherwise built. Matches the
U-Boot-stage and SPL-stage reference dtsi files already dropped
earlier.
Trim panel_description down to the single validated 60Hz mode instead
of 12 ambiguous candidate modes, and fix a stray extra byte in the
MIPI_DCS_EXIT_SLEEP_MODE init command (seq=1100 -> seq=11) that doesn't
match either the vendor-extracted panel-init-sequence or the old
removed ST7701 C-driver patch. Confirmed better on real hardware.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Every other PX30S-specific behavior difference from the vendor BSP
kernel already has a corresponding soc_is_px30s()-gated patch in this
series (023-025, 027-028) - clk-px30.c was the one gap, still
unconditionally using vanilla PX30's DDR PHY clock topology on PX30S
boards. On PX30S, clk_ddrphy1x is its own independently muxed/divided
clock rather than a fixed /4 of clk_ddrphy4x, and clk_stdby_2wrap runs
at a quarter of clk_ddrphy1x's rate instead of the same rate as it.

Ported from rockchip-linux/kernel commit f89c8138cab3, cross-checked
identical against both the develop-4.4 and develop-5.10 BSP branches.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Jacob-Matthew-Cook

Copy link
Copy Markdown
Author

Spent some time auditing every PX30S-specific difference in the vendor BSP kernel (rockchip-linux/kernel, checked against both develop-4.4 and develop-5.10 for consistency) against what's already ported here, focused on DVFS/clocks/power.

Found and fixed one real gap: clk-px30.c's DDR PHY/OTP clock topology. Every other PX30S subsystem difference already has a soc_is_px30s()-gated patch in this series (023-025, 027-028), but the clock driver itself was still unconditionally using vanilla PX30's topology on PX30S boards. On PX30S, clk_ddrphy1x is its own independently muxed/divided clock rather than a fixed /4 of a clk_ddrphy4x parent, and clk_stdby_2wrap runs at a quarter of clk_ddrphy1x's rate instead of the same rate as it - a genuinely different clock relationship, not just a rename. Ported from vendor commit f89c8138cab3 as 033-px30s-ddrphy-clock-topology.patch. This hasn't been hardware-tested yet - it applies cleanly and compiles, but I haven't confirmed it actually changes the RAM-corruption behavior we've been chasing separately.

Everything else already covered, for completeness:

  • GPU power domain (024) - already keeps pd_gpu from ever powering off on PX30S, plus skips genpd's generic clock tracking so it doesn't fight with mali_kbase's own clock management. Confirmed via dmesg this is real and necessary, but on its own it's not sufficient to explain the corruption either - it's been compiled into every image tested so far.
  • io-domain.c (pmuio1 1.8V/3.3V switch, 027), rockchip-otp.c (read protocol, 032), rockchip_thermal.c (calibration table, 023), MIPI/USB2 PHY tuning (025, 028) - all already ported, none of these are DVFS-relevant beyond thermal calibration accuracy.

One architectural difference with no fix planned, just noting it: the vendor BSP has an entire subsystem (rockchip_opp_select.c, ~2100 lines, no mainline equivalent) that measures each physical chip's actual speed/leakage at boot via a PVTM ring-oscillator hardware block, temperature-compensates it, and picks a voltage bin calibrated to that specific unit. Confirmed active (not dead code) on this exact board's vendor devicetree, for both CPU and GPU. Mainline/ROCKNIX has none of this and always uses the single safest/highest-margin voltage bin for every unit. Unlikely to be a source of instability (it errs toward more margin, not less), but worth knowing this device's real silicon was individually calibrated by vendor firmware in a way we don't replicate.

@Jacob-Matthew-Cook

Jacob-Matthew-Cook commented Jul 16, 2026

Copy link
Copy Markdown
Author

@Jacob-Matthew-Cook I tested the Alpha 1.3 build on real hardware. The first boot was completely normal. However, after changing the language and timezone in the Settings and performing a restart, the device gets stuck on a black screen (the backlight is on, but there is no display) right after the boot logo.

I think I found the issue. There were a few errors in the panel dts description provided by @stolen, which have been fixed. I am updating Alpha 1.3 again in-place, but I am placing the vendor CPU and GPU opp tables in place (which can go to much lower power levels).

The sleep issues seem to be some combination of voltage changing much too quickly for this chip following resume, which we haven't fully characterized. I will need to keep testing @labac-dev, but the in-place Alpha 1.3 update should fix the display.

I highly encourage people to try debugging and testing the system via SSH over USB (or UART, if they want to get panics closer the the kernel failure). Given the RAM can corrupt during voltage transitions, it is unlikely the UART can catch the exact cause of failure.

If the system is left in performance mode or powersave mode, suspend to memory works. Do be careful, as ondemand and schedutil can cause the system to crash following resume.

Lastly, you may notice overclocking from stock settings may reboot your device. If that is the case, you should enable CPU performance mode first, and THEN set the CPU overclock.

@aenertia

Copy link
Copy Markdown
Contributor

Did you implement TEO/Uclamp stack with Schedutil?s - I had to adjust the polling rate down of the freq to be stable for the xf40h and rk3566 work I was doing a few months to get stable results, the defaults poll too aggressively and trigger freq changes which cause crashes . schedutils is probably the right govt in general once dialed in with systemd and TEO, but you need the whole uclamp/teo/cgroupv2 stack setup properly. There should be some discussion on this buried in github from a few months back.

@Jacob-Matthew-Cook

Copy link
Copy Markdown
Author

Did you implement TEO/Uclamp stack with Schedutil?s - I had to adjust the polling rate down of the freq to be stable for the xf40h and rk3566 work I was doing a few months to get stable results, the defaults poll too aggressively and trigger freq changes which cause crashes . schedutils is probably the right govt in general once dialed in with systemd and TEO, but you need the whole uclamp/teo/cgroupv2 stack setup properly. There should be some discussion on this buried in github from a few months back.

I don't think I have TEO/Uclamp stack implemented. Also, the issue occurs with either Schedutil or Ondemand. I'll look into your points. How critical is BL32 in your opinion?

PR#2360 is eerily similar to what we are working through right now... very interesting:
#2360

@aenertia

aenertia commented Jul 17, 2026 via email

Copy link
Copy Markdown
Contributor

@Jacob-Matthew-Cook

Jacob-Matthew-Cook commented Jul 17, 2026

Copy link
Copy Markdown
Author

Yes - the DMC freq selection was part of what I took further and implemented; it's not really as relevant on the rk3326 as on the 3566. bl32 isn't relevant it was a red herring IIRC. There is probably some more advanced branches in my github repos.>

Interesting. Just a heads up, the Pixel2 uses the RK3326-S variant (not the RK3326 base), which is somewhat modernized and has overall better power performance (with a few newer features). It can support faster RAM if I am not mistaken, and I think it may have some similar structural aspects to newer SoCs from Rockchip. I'll keep looking into this as I have time.

If you have any technical input regarding DVFS on the Rockchip SoCs, that would be appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants