While reading megi's PinePhone Pro review I noticed that the PinePhone Pro eMMC is fast (~150MB/s), and began wondering why can't the original PinePhone eMMC (50-80MB/s) go that fast as well.
eMMC cards can use these timing modes:
Timing mode | eMMC version | Clock speed | Max data rate | Vccq voltage allowed |
---|---|---|---|---|
Legacy | >= 4.1 | 0-26MHz | 26MB/s | 3.3V, 1.8V, 1.2V |
DDR52 | >= 4.4 | 0-52MHz | 104MB/s | 3.3V, 1.8V, 1.2V |
HS200 | >= 4.5 | 0-200MHz | 200MB/s | 1.8V, 1.2V |
HS400 | >= 5.0 | 0-200MHz | 400MB/s | 1.8V, 1.2V |
A bit of investigation shows that the PinePhone eMMC is using the DDR52 timing mode. This explains why we get read speeds below 100MB/s.
# cat /sys/kernel/debug/mmc2/ios
clock: 52000000 Hz
actual clock: 50000000 Hz
vdd: 21 (3.3 ~ 3.4 V)
bus mode: 2 (push-pull)
chip select: 0 (don't care)
power mode: 2 (on)
bus width: 3 (8 bits)
timing spec: 8 (mmc DDR52)
signal voltage: 0 (3.30 V)
driver type: 0 (driver type B)
After searching in the datasheets from the Pine64 PinePhone wiki I figured out that both the Allwinner A64 and the Kimtigo eMMC support eMMC 5.0 standard, so they should be able to use the High Speed HS200/HS400 timings.
The eMMC timing mode is defined by the PinePhone Device Tree which is used by the Linux kernel to know the hardware configuration of a certain device.
The PinePhone base Device Tree, which is common to all board revisions can be found in the kernel
source in the arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
file.
This is the portion describing the eMMC:
&mmc2 {
pinctrl-names = "default";
pinctrl-0 = <&mmc2_pins>;
vmmc-supply = <®_dcdc1>;
vqmmc-supply = <®_dcdc1>;
bus-width = <8>;
non-removable;
cap-mmc-hw-reset;
post-power-on-delay-ms = <1>; /* power is already turned on by the bootloader */
status = "okay";
};
I have tried enabling HS200 mode by adding mmc-hs200-1_8v;
to the mmc2
block and the eMMC fails
the HS200 initialization and falls back to legacy mode.
$ dmesg | grep mmc
[ 0.661840] mmc2: mmc_select_hs200 failed, error -74
[ 0.717040] mmc2: new MMC card at address 0001
[ 0.718093] mmcblk2: mmc2:0001 DA4032 29.1 GiB
[ 0.718663] mmcblk2boot0: mmc2:0001 DA4032 4.00 MiB
[ 0.719119] mmcblk2boot1: mmc2:0001 DA4032 4.00 MiB
[ 0.721260] mmcblk2: p1 p2
[ 2.048130] pmos_boot=/dev/mmcblk0p1
[ 2.048136] pmos_root=/dev/mmcblk0p2
# cat /sys/kernel/debug/mmc2/ios
clock: 25000000 Hz
actual clock: 25000000 Hz
vdd: 21 (3.3 ~ 3.4 V)
bus mode: 2 (push-pull)
chip select: 0 (don't care)
power mode: 2 (on)
bus width: 3 (8 bits)
timing spec: 0 (legacy)
signal voltage: 1 (1.80 V)
driver type: 0 (driver type B)
eMMC cards are managed NAND devices, they contain one or mode NAND chips and a micro-controller which takes care of wear leveling and other operations required by NAND storage and exposes a block device to the host.
eMMC cards have two power supply lines:
- Vcc powering the NAND memories
- Vccq powering the micro-controller and MMC interface.
In the eMMC timing table above you can see that HS200/HS400 modes are not allowed when Vccq is powered at 3.3V, and looking at the PinePhone schematic, we see that the PinePhone has Vccq set to 3.3V.
This is the reason why HS200 doesn't work on the PinePhone.
Hardware modification
This modification involves desoldering and soldering components on the PinePhone mainboard, do this only if you feel confident with the procedure.
I take no resposibility for eventual damage.
This modification requires support from the Linux distribution you are using, as the Device Tree needs to be patched to reflect the hardware change. PostmarketOS supports this with the package
device-pine64-pinephone-vccq-mod
, if you use other Linux distros, get in touch with them to know if the mod is supported.
After performing this modification you won't be able to boot from eMMC any Linux image that is missing the proper Device Tree Overlay, this limitation does not apply to the microSD slot.
If we look at the schematics and the component placement files from the Pine64 PinePhone wiki, we can see that there is a 0 ohm resistor R615 that can be moved to a Not Connect footprint R614, to switch Vccq from a 3.3V regulator (DCDC1) to a 1.8V regulator (ELDO1).
The steps to perform the hardware mod are the following:
- Disassemble the PinePhone and remove the mainboard from the phone
- Remove the metallic RF shield from the mainboard side with the A64 SoC visible at the center.
- Locate R615 and R614 footprints with the help of the component placement drawing for your PP revision. Hint: the R615 resistor is above the eMMC card, and the R614 footprint should be right above it.
- Desolder R615 0 ohm resistor and solder it to R614, or bridge R614 with solder.
- Put back the metallic RF shield paying attention to the alignment
- Reassemble the PinePhone
- Reinstall PostmarketOS to the eMMC selecting the device-pine64-pinephone-vccq-mod as package to be installed during pmbootstrap init
See the postmarketOS PinePhone wiki page for details.
Software support
After performing the mod, the PinePhone Device Tree will not correspond to our PinePhone hardware, because we have moved Vccq from a 3.3V regulator to a 1.8V one, and we need to enable HS200 mode to get advantage of the additional speed.
To do this and maintain compatibility with non modified PinePhones I created the
device-pine64-pinephone-vccq-mod
packet (postmarketOS Merge
Request)
The package has to temporarily change the Device Tree, it does this by using a Device Tree Overlay, that gets loaded by the U-boot bootloader before starting the Linux kernel.
This is the Device Tree Overlay we need:
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
// Copyright (C) 2021 Federico Amedeo Izzo <federico@izzo.pro>
// Switch eMMC Vccq from 3.3v regulator DCDC1 to 1.8v regulator ELDO1
// And enable HS200 mode.
// This DT overlay should be applied only after modifying the Pinephone
// Board by moving R615 to R614.
/dts-v1/;
/plugin/;
/ {
compatible = "pine64,pinephone";
};
&mmc2 {
pinctrl-0 = <&mmc2_pins>, <&mmc2_ds_pin>;
vqmmc-supply = <®_eldo1>;
mmc-hs200-1_8v;
};
&pio {
vcc-pc-supply = <®_eldo1>;
};
To apply this device tree only after installing the device-pine64-pinephone-vccq-mod
I had to
change the U-boot configuration.
The PinePhone is using U-boot in a read-only mode, as U-boot environment variables are not
persistent, they are restored to default values at each boot, and the boot procedure itself is
managed by a boot.scr
script, that is executed at each boot.
I think that this is a good decision as having read-only variables means that U-boot is stateless and cannot get corrupted by changing the variables.
To change the U-boot behaviour, by suggestion of Martijn Braam I used the
source
command in boot.scr
to load a user script that loads the Device Tree Overlay.
If the user script is not found, the source
command is skipped.
This section was added to the main boot.scr
echo Loading user script
setenv user_scriptaddr 0x50100000
load mmc ${mmc_bootdev}:1 ${user_scriptaddr} user.scr
if test $? -eq 0; then source ${user_scriptaddr}; else echo No user script found; fi
And this is the secondary user.scr
script
echo Entering user script:
echo Loading DTB overlay
load mmc ${mmc_bootdev}:1 ${fdtoverlay_addr_r} pinephone-vccq-mod.dtbo
echo Applying DTB overlay
fdt apply ${fdtoverlay_addr_r}
echo Exiting user script:
By applying the change on boot.scr
by default and installing the user.scr
and Device Tree
Overlay with the device-pine64-pinephone-vccq-mod
, the software support is complete.
Speed measurements
The read speed of your eMMC or other storage device can be measured with the hdparm
command.
Replace /dev/mmcblk2
with the device you want to mesure, and only consider the buffered speed.
# hdparm -tT /dev/mmcblk2
/dev/mmcblk2:
Timing cached reads: 1038 MB in 2.00 seconds = 518.44 MB/sec
Timing buffered disk reads: 376 MB in 3.00 seconds = 125.13 MB/sec
Here are the results on the two PinePhones I modified:
- PinePhone 1.2 pmOS CE (convergence package) with 32GB SanDisk eMMC:
before 55MB/s, after 125MB/s - PinePhone 1.0 Braveheart edition with 16GB Kimtigo eMMC:
before: 80MB/s, after 110MB/s
Future improvements:
HS400 mode is supported by hardware but it's not currently supported by the sunxi-mmc
drivers in the Linux kernel.
Adding support for HS400 mode could bring speed improvements, but there is a caveat:
From the Allwinner A64 SoC datasheet we can see that the eMMC clock is limited to 150MHz in HS200 mode and 100MHz in HS400 mode, so the speed improvements depend on whether it's higher the speed gain from HS400 or the speed penalty from the clock reduction.