====== DDR Frequency Switching on PineTab2 / RK3566 (LPDDR4) ======
This page documents how to change the **DDR frequency** on the
**Pine64 PineTab2 v2.0** (Rockchip **RK3566**, **8 GB LPDDR4** as 2x 4 GB)
by swapping the rkbin TPL DDR-init blob, and records the **production-stable
1332 MT/s** operation observed on **ohm** (mfritsche's PineTab2 v2.0).
Sibling page: [[megabitchip:ddr_frequency_switching|DDR frequency switching on RK3588 (LPDDR5)]] — same methodology framework, RK3588-/LPDDR5-specific blobs and offsets. Read both if you are working across the family.
**Flashing a bad DDR blob bricks boot.** Recovery requires either booting
from an SD card with a known-good ''idbloader.img'' (PineTab2 boots SD
before eMMC) or putting the tablet into **MASKROM** mode and reflashing
over USB from a host machine. A dedicated MASKROM-recovery page does not
yet exist on this wiki — **TODO**: create ''megabitchip:maskrom_recovery''
(both the RK3588 and RK3566/PineTab2 mechanisms differ — PineTab2 has a
dedicated **MASKROM hardware switch**, unlike the PinePhone and earlier
Pine64 devices which rely on shorting a flash pin).
===== 1. Stock and observed frequencies =====
==== Stock ====
The danctnix ''uboot-pinetab2'' package (version **2026.04-4** at time of
writing) ships with ''rk3566_ddr_1056MHz_v1.23.bin'':
^ Blob ^ DPLL ^ Data Rate ^ BW/ch ^ Status ^
| ''rk3566_ddr_1056MHz_v1.23.bin'' | 528 MHz | **1056 MT/s** | ~4.2 GB/s | danctnix default |
==== Verified upgrade ====
^ Blob ^ DPLL ^ Data Rate ^ BW/ch ^ Status ^
| ''rk3568_ddr_1332MHz_v1.23.bin'' | 666 MHz | **1332 MT/s** | ~5.3 GB/s | **VERIFIED stable on ohm** |
**+26 % memory bandwidth** vs. stock, currently running on ohm. Validation:
50+ minutes of ''memtester 4G 1'' with all 10+ completed patterns clean
(Stuck Address, Random Value, Compare XOR/SUB/MUL/DIV/OR/AND, Sequential
Increment, Solid Bits, partial Block Sequential), no EDAC / MCE / kernel
panic in dmesg.
==== Hardware ceiling ====
**1332 MT/s is the documented ceiling for this silicon.** Both
''rk3568_ddr_1560MHz_v1.23.bin'' and ''rk3568_ddr_1560MHz_D4_LP4_4x_eyescan_v1.23.bin''
were tested with structurally-validated SPL packaging (see §4) and
**do not train** on RK3566 — ohm fails to boot, no recovery without
MASKROM. Do not waste a session on 1560.
===== 2. Available rkbin v1.23 blobs for RK3566 =====
From ''~/src/rkbin/bin/rk35/'' on ohm (and on a clone of
[[https://github.com/rockchip-linux/rkbin|rockchip-linux/rkbin]]):
^ Blob ^ Rate ^ Notes ^
| ''rk3566_ddr_528MHz_ultra_v1.10.bin'' | 528 MT/s | very low |
| ''rk3566_ddr_780MHz_ultra_v1.10.bin'' | 780 MT/s | low |
| ''rk3566_ddr_920MHz_ultra_v1.10.bin'' | 920 MT/s | older |
| ''rk3566_ddr_920MHz_v1.23.bin'' | 920 MT/s | v1.23 conservative |
| ''rk3566_ddr_1056MHz_ultra_v1.20.bin'' | 1056 MT/s | alt |
| **''rk3566_ddr_1056MHz_v1.23.bin''** | **1056 MT/s** | **danctnix default** |
| ''rk3568_ddr_920MHz_v1.23.bin'' | 920 MT/s | RK3568 cross-blob, works on RK3566 |
| ''rk3568_ddr_1056MHz_v1.23.bin'' | 1056 MT/s | RK3568 cross-blob |
| **''rk3568_ddr_1332MHz_v1.23.bin''** | **1332 MT/s** | **VERIFIED on PineTab2 — recommended** |
| ''rk3568_ddr_1560MHz_v1.23.bin'' | 1560 MT/s | does NOT train on RK3566 silicon |
| ''rk3568_ddr_1560MHz_D4_LP4_4x_eyescan_v1.23.bin'' | 1560 MT/s | does NOT train (eyescan variant tried) |
The ''rk3568_'' blobs work on RK3566 because the two SoCs share their DDR
controller IP; the rkbin RK3568 toolchain happens to ship the higher
frequency points the RK3566 line does not.
===== 3. Build recipe (mkimage -T rksd) =====
The danctnix ''idbloader.img'' is a Rockchip RKSD container with two
parts: the **DDR init blob** (TPL, 4 KB scrambled header + payload) and
the **SPL** (U-Boot SPL stage). To switch frequency, repack the same SPL
with a different DDR blob.
DDR=~/src/rkbin/bin/rk35/rk3568_ddr_1332MHz_v1.23.bin # or 1056/920/780/528 etc.
SPL=~/ohm-recovery/uboot-spl-correct.bin # extracted from danctnix
# idbloader.img with skip=61440
mkimage -n rk3568 -T rksd -d $DDR:$SPL \
~/ohm-recovery/idbloader-1332-FIXED.img
The ''-n rk3568'' name argument is correct even on RK3566 — the rkbin
TPL key matches the RK3568 line. The output is bit-for-bit consumable by
the BootROM the same way the danctnix ''idbloader.img'' is.
===== 4. Critical SPL-extraction gotcha =====
**The ''dd skip='' for extracting the SPL from danctnix ''idbloader.img''
must be exactly 61440 (= sector 120 × 512), NOT 63488.**
Sector 120 is recorded in the **RKNS header at byte 0xd0** of the
danctnix ''idbloader.img''. Naively assuming a 4-sector pad-up of the
DDR region (which would land at 63488) silently truncates the SPL by
**2 KB**, and the resulting ''idbloader.img'' bricks on flash —
**looking exactly like a DDR-training failure** at the device.
==== Validation procedure ====
To prove that a freshly-extracted SPL + your packaging recipe are
**structurally sound** before risking a frequency change, build a 1056
variant **with the same SPL+recipe** and confirm:
md5sum ~/ohm-recovery/idbloader-1056-FIXED.img
# must equal: ceb4d3fdfb7252e0815d24694e9043b4 (the danctnix golden)
If the md5 matches, the SPL extraction and ''mkimage'' recipe are
correct, and **only the DDR portion** can fail at the device. If the
md5 does not match, the SPL is wrong — fix the extraction first; do
not flash. This is the procedure that retroactively explained ohm's
1560 MT/s bricking as a genuine DDR-training failure (and not an SPL
truncation), because the parallel 1056-FIXED build matched the
danctnix golden md5 byte-for-byte.
===== 5. Flash procedure (eMMC, danctnix layout) =====
Two raw offsets in the pre-GPT region (GPT starts at sector 65536):
^ Component ^ eMMC sector ^ Byte offset ^
| ''idbloader.img'' | 64 | 32 KB |
| ''u-boot.itb'' | 16384 | 8 MB |
==== Path A — boot-from-SD (safest) ====
- Write the new ''idbloader--FIXED.img'' to a danctnix-bootable SD card's sector 64.
- Insert SD into PineTab2, power on. The PineTab2 BootROM tries SD before eMMC, so a bad DDR blob on SD **cannot** brick the device — just remove the SD and the eMMC keeps booting.
- If SD boots successfully, you have validated the blob on this physical hardware. Now mirror to eMMC (Path B).
==== Path B — direct eMMC write from a running ohm ====
sudo dd if=~/ohm-recovery/idbloader-1332-FIXED.img \
of=/dev/mmcblk0 bs=512 seek=64 count=420 conv=fsync
sudo cp ~/ohm-recovery/idbloader-1332-FIXED.img /boot/idbloader.img
sudo sync
sudo reboot
The ''/boot/idbloader.img'' copy keeps initramfs-rebuild / kernel-package
hooks consistent with the on-disk raw region.
**Failure mode for Path B = MASKROM + meitner.** Do not skip Path A on
the first build of a frequency you have not previously verified.
===== 6. Recovery procedures =====
==== 6.1 SD-boot recovery (preferred) ====
From a danctnix-bootable SD on ohm:
sudo dd if=/path/to/idbloader-1056-FIXED.img \
of=/dev/mmcblk0 bs=512 seek=64 count=420 conv=fsync
sudo cp /path/to/idbloader-1056-FIXED.img /boot/idbloader.img
sudo sync
sudo reboot
Remove the SD before reboot completes so the device boots from the
freshly-rewritten eMMC.
==== 6.2 MASKROM + rkdeveloptool from meitner (flaky) ====
- Trigger MASKROM via the **dedicated MASKROM hardware switch** on the PineTab2. //(This is the one significant divergence from PinePhone / earlier Pine64 devices, which rely on shorting a flash pin or holding a button — note this clearly when documenting recovery for future readers.)//
- On meitner, build [[https://github.com/rockchip-linux/rkdeveloptool|rockchip-linux/rkdeveloptool]] **from master**. The prebuilt ''rkdeveloptool 1.32'' has trouble with NEWIDB v1.23 blobs — the ''wl'' step succeeds maybe half the time. Be prepared to retry.
- Push the loader and write the idbloader:
# On meitner, with PineTab2 in MASKROM connected over USB-C:
rkdeveloptool db MiniLoaderAll.bin
# wait ~15-20 s for USB-MSC to come up
rkdeveloptool wl 64 idbloader.img
rkdeveloptool rd 0
''MiniLoaderAll.bin'' is the Pine64-supplied loader from
[[https://pine64.org/documentation/PineTab2/files/MiniLoaderAll.bin.zip|pine64.org]].
===== 7. Runtime DVFS =====
**Mainline kernel does NOT have a DMC devfreq driver wired for the
PineTab2 DT.** Whatever frequency the TPL programs at boot is the
steady-state frequency. There is **no runtime scaling** and **no
runtime safety net** that would drop to a lower step if the chosen
frequency becomes unstable. Treat the boot blob as the only frequency
the system will ever see.
===== 8. Safety notes =====
* **Always run the §4 md5 validation.** A mis-extracted SPL fails identically to a mis-trained DDR — you will misdiagnose for hours otherwise.
* **Always do Path A (SD boot) before Path B (direct eMMC)** for any frequency you have not previously verified on the specific physical device.
* **1332 is the ceiling.** Do not retry 1560 expecting a different result on PineTab2 silicon.
* **No DMC devfreq on mainline = boot frequency is forever.** No kernel-side fallback if a marginal blob is silently flaky under thermal stress months later.
* **Thermals matter.** 1332 MT/s raises per-channel bandwidth ~26 % over the 1056 MT/s default; sustained-load temps should be checked before declaring stable in a hot ambient.
===== See also =====
* [[megabitchip:start|MegabitChip running index]]
* [[megabitchip:ddr_frequency_switching|DDR frequency switching on RK3588 (LPDDR5)]] — sibling page, same framework, different SoC family
* [[https://github.com/rockchip-linux/rkbin|rockchip-linux/rkbin]] — upstream Rockchip blob repo
* [[https://github.com/rockchip-linux/rkdeveloptool|rockchip-linux/rkdeveloptool]] — MASKROM USB tool (build from master, 1.32 prebuilt is flaky on NEWIDB v1.23)
* [[https://pine64.org/documentation/PineTab2/files/MiniLoaderAll.bin.zip|MiniLoaderAll.bin]] — Pine64-supplied MASKROM loader for PineTab2
* **TODO:** ''megabitchip:maskrom_recovery'' (not yet created) — full MASKROM recovery procedure for both RK3588 and RK3566/PineTab2 (note the PineTab2-unique hardware MASKROM switch)