Skip to content

lib: zstd: update to latest Linux zstd 1.5.7 - #37

Open
Inhertz wants to merge 58 commits into
flipperdevices:rk3576from
Inhertz:zstd-1.5.7
Open

lib: zstd: update to latest Linux zstd 1.5.7#37
Inhertz wants to merge 58 commits into
flipperdevices:rk3576from
Inhertz:zstd-1.5.7

Conversation

@Inhertz

@Inhertz Inhertz commented Jul 21, 2026

Copy link
Copy Markdown

What's new

zstd 1.5.7 Ported. Closes #36

Verification

The following tests were performed:

  • clean builds of sandbox, sandbox64, am62x_evm_a53 (aarch64) and sandbox with ZSTD_LIB_MINIFY=n
  • ut lib compression_test_zstd and compression_test_bootm_zstd: pass
  • imxtract of a FIT subimage compressed with upstream zstd 1.5.7 (python-zstandard), decompressed output crc32-verified against the original payload
  • sqfsload of a file from a zstd-compressed squashfs, crc32-verified
  • Real hardware: RAM-booted this branch on an Orange Pi 5B (RK3588S) via maskrom/USB, loaded a zstd-1.5.7-compressed FIT payload from a USB stick with imxtract, CRC32 matched.

Contributor checklist

  • I have read the changes in this PR and understand what they do
  • I can explain the approach taken and why alternatives were not chosen
  • I have tested these changes myself (on hardware or in simulation)
  • I am able to respond to review comments on my own, not by forwarding them to an AI

If you used AI tools to assist with this PR, that is fine — but the checklist above still applies to you personally.

Disclaimer

This is my first contribution to FOSS, I appreciate any feedback. I used Claude Fable 5 as a tool, every code line changed was reviewed at a high level since it is a porting. Testing was performed both by simulation using my main PC with CatchyOS and my Orange Pi 5B with RK3588 since i do not have RK3576. Any further testing request on RK3588 is welcomed.

image results

Commit Message

Update the zstd implementation to match Linux v6.15's lib/zstd, which imports upstream zstd 1.5.7 in Linux commit 65d1f5507ed2 ("zstd: Import upstream v1.5.7") and includes the follow-up workaround from Linux commit 1400c87e6cac ("zstd: Increase DYNAMIC_BMI2 GCC version cutoff from 4.8 to 11.0 to work around compiler segfault").

As with the previous 1.5.2 import (commit 4b9b25d), this is a straight mirror of the Linux zstd code, except to:

  • update a few #include that do not translate cleanly
    • linux/unaligned.h -> asm/unaligned.h (Linux moved this header in commit 5f60d5f6bbc1)
    • linux/swab.h -> asm/byteorder.h
    • linux/limits.h -> linux/kernel.h
    • linux/module.h -> linux/compat.h
  • remove assert() from debug.h so it doesn't conflict with u-boot's assert()
  • strip out the compressor code as was done in the previous u-boot zstd
  • change the #define for MEM_STATIC to use INLINE_KEYWORD/UNUSED_ATTR for codesize
  • drop ZSTD_SRCSIZEHINT_MAX (needs INT_MAX from linux/limits.h) as was done in the previous import
  • collapse consecutive blank lines to keep checkpatch happy

New files in this sync: lib/zstd/common/allocations.h and lib/zstd/common/bits.h. The decompress-only object list in lib/zstd/Makefile and the CONFIG_ZSTD_LIB_MINIFY ccflags are unchanged from the 1.5.2 import. The kernel-style wrapper API in include/linux/zstd.h is source-compatible, so lib/zstd/zstd.c and fs/squashfs/sqfs_decompressor.c need no changes.

Tested with:

  • clean builds of sandbox, sandbox64, am62x_evm_a53 (aarch64) and sandbox with ZSTD_LIB_MINIFY=n
  • ut lib compression_test_zstd and compression_test_bootm_zstd: pass
  • imxtract of a FIT subimage compressed with upstream zstd 1.5.7 (python-zstandard), decompressed output crc32-verified against the original payload
  • sqfsload of a file from a zstd-compressed squashfs, crc32-verified
  • Real hardware: RAM-booted this branch on an Orange Pi 5B (RK3588S) via maskrom/USB, loaded a zstd-1.5.7-compressed FIT payload from a USB stick with imxtract, CRC32 matched.

Kwiboo and others added 30 commits July 13, 2026 11:02
Split 32-bit size_and_off and size_and_nimage fields of the v2 image
format header into their own 16-bit size, offset and num_images fields.

Set num_images based on number of images passed by the datafile
parameter and size based on the offset to the hash field to fix using a
single init data file and no boot data file for the v2 image format.

Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Signed-off-by: Alexey Charkov <alchark@flipper.net>
The v2 image format can embed up to 4 data files compared to the two
init and boot data files using the older image format.

Add support for displaying more of the image header information that
exists in the v2 image format, e.g. image load address and flag.

Example for v2 image format:

  > tools/mkimage -l rk3576_idblock_v1.09.107.img
  Rockchip Boot Image (v2)
  Image 1: 4096 @ 0x1000
  - Load address: 0x3ffc0000
  Image 2: 77824 @ 0x2000
  - Load address: 0x3ff81000
  Image 3: 262144 @ 0x15000

Example for older image format:

  > tools/mkimage -l u-boot-rockchip.bin
  Rockchip RK32 (SD/MMC) Boot Image
  Init Data: 20480 @ 0x800
  Boot Data: 112640 @ 0x5800

Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Signed-off-by: Alexey Charkov <alchark@flipper.net>
The v2 image format embeds boot0 and boot1 parameters, the vendor tool
boot_merger may write these parameters based on the rkboot miniall.ini
files.

E.g. a RK3576 boot image may contain a boot1 parameter that signals
BootROM or vendor blobs to use 1 GHz instead of the regular 24 MHz rate
for the high precision timer.

Add support for printing boot0 and boot1 parameters, e.g.:

  > tools/mkimage -l rk3576_idblock_v1.09.107.img
  Rockchip Boot Image (v2)
  Boot1 2: 0x100
  Image 1: 4096 @ 0x1000
  - Load address: 0x3ffc0000
  Image 2: 77824 @ 0x2000
  - Load address: 0x3ff81000
  Image 3: 262144 @ 0x15000

Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Signed-off-by: Alexey Charkov <alchark@flipper.net>
The vendor boot_merger tool support a ALIGN parameter that is used to
define offset alignment of the embedded images.

Vendor use this for RK3576 to change offset alignment from the common
2 KiB to 4 KiB, presumably it may have something to do with UFS.
Testing with eMMC has shown that using a 512-byte alignment also work.

Add support for overriding offset alignment in case this is needed for
e.g. RK3576 in the future.

Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Signed-off-by: Alexey Charkov <alchark@flipper.net>
The v2 image format can support up to 4 embedded images that can be
loaded by the BootROM using the back-to-bootrom method.

Currently two input files can be passed in using the datafile parameter,
separated by a colon (":").

Extend the datafile parameter parsing to support up to 4 input files
separated by a colon (":") for use with the v2 image format.

Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Signed-off-by: Alexey Charkov <alchark@flipper.net>
The v2 image format supports defining a load address and flag for each
embedded image.

Add initial support for writing the image load address and flag to the
v2 image format header.

This may later be used for RK3576 to embed a minimal initial image that
if required to fix booting from SD-card due to a BootROM issue.

Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Signed-off-by: Alexey Charkov <alchark@flipper.net>
The BootROM on RK3576 has an issue loading boot images from an SD-card.
This issue can be worked around by injecting an initial boot image
before TPL that:

  writel(0x3ffff800, 0x3ff803b0)

Prepend an image containing binary code that does this and return to
BootROM to load next image, TPL.

Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
[switch from pre-built binary to from-source build via existing Makefiles]
Signed-off-by: Alexey Charkov <alchark@flipper.net>
NanoPi M5 uses the M1 pin configuration for its serial flash controller.
Set the pin mode to M1 explicitly to enable SPL loading from SPI flash.

Signed-off-by: Alexey Charkov <alchark@gmail.com>
RK3576 EVB1 is the evaluation board for the RK3576 SoC, which also serves
as the reference design for board vendors.

Enable building images for it using upstream DTS and a minimal defconfig.

Signed-off-by: Alexey Charkov <alchark@gmail.com>
Introduce CONFIG_USB_FUNCTION_FASTBOOT_EP_BUFFER_SIZE to allow
customization of the endpoint buffer size used for fastboot transfers.

The EP_BUFFER_SIZE must always be an integral multiple of the maxpacket
size (64, 512, or 1024 bytes depending on USB speed), as controllers
like DWC3 expect bulk OUT requests to be divisible by maxpacket size.

On DWC3 controllers operating in SuperSpeed mode, increasing the
endpoint buffer size from the default value significantly improves
download throughput - from approximately 50 MB/s to over 170 MB/s.
This is particularly beneficial for flashing large images during
development or production.

The configurable buffer size allows board maintainers to tune the
trade-off between memory usage and transfer performance based on
their specific requirements and available resources.

Change-Id: 0c3402e0-3855-4d3f-b6c1-293793eebc4a
Signed-off-by: Anton Burticica <mouse@ya.ru>
This change will go via the upstream DTS tree, so just put it in here
temporarily to get Ethernet working on Omni3576 boards.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
Remove the supply regulators from the eMMC controller node on Luckfox
Core3576, as they cause the eMMC to endlessly re-tune phase at startup,
and are most likely wrong:

1. The vendor DTS doesn't define those regulators
2. The VCCQ regulator referenced here is actually used for the SD card,
   and it is unlikely that both can share the same regulator with an
   1.8-3.3V range, whereas eMMC only expects 1.8V
3. Rockchip reference schematic, which this board broadly follows,
   drives the VCCQ supply of eMMC flash from VCC_1V8_S0 rather than
   VCCIO_SD_S0, where VCC_1V8_S0 is a fixed 1.8V load switch with VIN tied
   to VCC_1V8_S3 and EN tied to VCCA_1V8_S0 (a.k.a. PMIC PLDO1, not PLDO5)

There is no published schematic for the Core3576 SoM unfortunately.

Cc: stable@vger.kernel.org
Fixes: d7ad90d22abe ("arm64: dts: rockchip: Add Luckfox Omni3576 Board support")
Signed-off-by: Alexey Charkov <alchark@flipper.net>
Signed-off-by: Alexey Charkov <alchark@flipper.net>
The gpt_fill_header() function was incorrectly calculating the
last_usable_lba value using a hardcoded assumption about the partition
table entry (PTE) area size. This caused incorrect backup GPT placement
on disks with non-512-byte sector sizes.

The GPT specification requires 128 partition entries × 128 bytes = 16384
bytes for the partition entry array. For 512-byte sectors this requires
32 sectors, but for 4096-byte sectors only 4 sectors are needed.

Introduce a local pte_sectors variable that dynamically calculates the
number of sectors required for the partition entries based on the actual
block size:

    pte_sectors = DIV_ROUND_UP(GPT_ENTRY_NUMBERS * sizeof(gpt_entry),
                               desc->blksz);

This ensures:
- last_usable_lba correctly reserves space for backup GPT header (1 block)
  plus backup partition entries (pte_sectors blocks)
- first_usable_lba correctly accounts for the primary partition entries
  starting at partition_entry_lba

The fix is essential for:
- Disks with 4K native sector size (i.e. UFS flashes)
- Proper GPT compliance across all sector size configurations

Change-Id: faf3cb2e-056d-458d-8abe-61edf2f40384
Signed-off-by: Anton Burticica <mouse@ya.ru>
Update FASTBOOT_COMMAND_LEN and FASTBOOT_RESPONSE_LEN to match the
buffer sizes defined in the Android fastboot client:

  https://android.googlesource.com/platform/system/core/+/refs/heads/main/fastboot/constants.h

  #define FB_COMMAND_SZ  4096
  #define FB_RESPONSE_SZ  256

The original 64-byte command limit dates back to the early fastboot
protocol specification. Modern Android fastboot clients support
commands up to 4096 bytes, enabling:
- Longer partition names in flash/erase commands
- Extended getvar queries with complex arguments
- OEM commands with substantial payloads

Change-Id: 1aaaa615-0811-4f81-949c-1ae4b9935fb0
Signed-off-by: Anton Burticica <mouse@ya.ru>
… consoles

The bitmap console driver does not implement ops->measure, so
vidconsole_measure() fell back to returning a single-line bounding box
(y1 = y_charsize) with x1 = x_charsize * strlen(text), regardless of
any pixel-width limit passed by the caller.

This caused Expo scene objects using CENTRE or RIGHT alignment to
compute incorrect x offsets for long strings.  For example, the ~68-
character help prompt on a 220 px wide scene produced:
  x1 = 6 * 68 = 408 px, xofs = (220 - 408) / 2 = -94 px
pushing the text ~94 pixels off the left edge of the display.

Add a word-wrapping fallback that is taken when a pixel-width limit is
provided and the caller requests line records (lines != NULL).  The
fallback iterates character-by-character, breaks at the last space
before an overflow, and populates the vidconsole_mline array and the
overall bbox.y1 in the same way a truetype driver would, so that callers
that lay out text using the returned metrics (e.g. scene_render_txt)
produce correctly wrapped, on-screen output.
Add a simple video uclass driver for the Flipper One's 256x144 8-bit
grayscale SPI display. The display accepts a full frame in the BPP8 format
(8-bit grayscale) in a single SPI write transaction, padded to a line
stride of 258 bytes (256 pixels + 2 footer bytes per row).

No other configuration is required as long as SPI mode 3 (CPOL=1, CPHA=1)
is used and the SPI clock is up to 24 MHz.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
Flipper One has an onboard MCU which exposes its front panel buttons over
the I2C interconnect bus.

Add a small keyboard driver to use these buttons for menu navigation.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
This will ultimately need to come from upstream, but for now we need to
get it in here so that we can build a working image for the device.

Drop DP nodes for now, as they are not yet included in rk3576.dtsi
in its U-boot version.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
Flipper One is a portable multi-tool device with a built-in display and
various interfaces, built around the Rockchip RK3576 SoC.

Add a new defconfig file for building U-Boot for this device.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
… PHY

dwc3_glue_probe() currently fetches the "usb3-phy" handle and calls
generic_phy_init() on it as the very first thing, before the glue's own
clocks and resets are touched. Only afterwards does it call
dwc3_glue_clk_init() and dwc3_glue_reset_init(), and later still
generic_phy_power_on().

For most platforms this happens to work because the controller has been
held in reset since power-on, so whatever state it presents on its PIPE
interface is benign while the PHY runs its bring-up sequence.

It breaks, however, when an earlier stage has already taken the
controller out of reset. A typical case is the Rockchip BootROM in USB
download (Maskrom) mode on RK3576: it leaves USB3OTG0 active so that it
can talk to the host over USB 2.0, which means the DWC3 wrapper is
clocked and out of reset by the time U-Boot probes it. The wrapper then
keeps driving phy_reset / phy_powerdown / phy_rate / etc. into the
USBDP combo PHY's PMA while rk3588_udphy_init() tries to bring up the
LCPLL, which never reaches AFC/LOCK_DONE and times out with:

  rockchip_udphy phy@2b010000: cmn ana lcpll lock timeout
  rockchip_udphy phy@2b010000: failed to init usbdp combophy

Linux's dwc3-of-simple deasserts the glue resets and enables the glue
clocks in its own probe, and only then calls of_platform_populate(), so
the dwc3 child (and therefore phy_init()) cannot run until the wrapper
is in a known state. Mirror that ordering here by moving the clk/reset
init ahead of generic_phy_init().

This is a prerequisite for any per-compatible "pulse the reset before
deasserting it" fix in dwc3_glue_reset_init() to actually take effect
on platforms where the controller may be left running by an earlier
boot stage. With the old ordering, such a pulse would happen after the
PHY had already failed its LCPLL poll and would have no effect.

No functional change is expected on platforms where the controller is
already in reset at probe time.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
dwc3_glue_reset_init() currently only calls reset_deassert_bulk() on
the resets it has just acquired (with a pre-existing assert+udelay
exception for "qcom,dwc3"). If the controller has already been taken
out of reset by an earlier boot stage, deasserting an already-deasserted
reset is a no-op, and the glue probe leaves whatever state that stage
left behind in place.

This becomes a problem when the controller has been actively used
before U-Boot runs. For example, on Rockchip RK3576 the BootROM keeps
USB3OTG0 powered up and clocked while it talks to the host in USB
download (Maskrom) mode. With the controller still alive on its PIPE
interface, the subsequent USBDP combo PHY bring-up cannot reliably get
its LCPLL to lock and the PHY .init callback fails with:

  rockchip_udphy phy@2b010000: cmn ana lcpll lock timeout

Drop the qcom-only special case and always assert the reset, wait
briefly, then deassert it. A bulk-assert followed by a small delay and
a bulk-deassert is harmless on platforms where the controller was
already in reset (the reset just gets re-pulsed before the rest of the
glue runs), and forces the controller into a known state on platforms
where it was not.

This relies on the preceding reordering of dwc3_glue_probe() so that
the glue resets are toggled before generic_phy_init() runs; otherwise
the PHY would already have observed the stale controller state and
failed before this code is reached.

Closes: https://lore.kernel.org/u-boot/CAKTNdwGo434ShEsP=e=uUAbJzVxfQPPfNPeTxOOqwbuoCyzRjw@mail.gmail.com/
Signed-off-by: Alexey Charkov <alchark@flipper.net>
Add the missing parameter and enum value descriptions reported by
scripts/kernel-doc when building with W=1:

  - get_relfile():           document @type
  - get_pxelinux_path():     document @pxefile_addr_r
  - enum lex_state:          document L_NORMAL, L_KEYWORD, L_SLITERAL
  - get_token():             document @t and @State

No functional change.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
The Boot Loader Specification [1] type flipperdevices#2 entry files use the keyword
"options" for the kernel command line, which corresponds to extlinux's
"append". Recognising it here lets the existing pxelinux parser ingest
BLS entries unchanged, paving the way for a BLS bootmeth that reuses
the parser instead of duplicating it.

No effect on existing extlinux/pxelinux files: "options" is not a valid
keyword in those formats, so it cannot collide with prior usage.

[1] https://uapi-group.org/specifications/specs/boot_loader_specification/

Signed-off-by: Alexey Charkov <alchark@flipper.net>
Split the body of parse_label() into a standalone parse_label_keys()
helper that walks key/value lines and populates a pre-existing
struct pxe_label. parse_label() becomes a thin wrapper that creates
the label, reads its name, attaches it to the menu, and delegates.

This is a pure refactor: the new helper contains the original loop
verbatim, with the local variable declarations moved to its scope.
No call sites or behaviour change.

A subsequent change will export this helper so callers parsing
formats that lack a 'label' header (notably Boot Loader Specification
type flipperdevices#2 entries) can populate a label directly from a file body
without duplicating the parser.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
Drop the static qualifier from label_create(), label_destroy(),
parse_label_keys() and label_boot(), and declare them in
<pxe_utils.h> to make them reusable.

The intended consumer is a Boot Loader Specification bootmeth, where
each on-disk file under loader/entries/ is a single entry with no
'label' header and no menu to traverse: the bootmeth derives the
label name from the filename, hands the file body to
parse_label_keys(), and invokes label_boot() directly.

No behaviour change: the implementations are unchanged and existing
in-tree callers in pxe_utils.c continue to use them as before.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
The parser currently treats any keyword it does not recognise inside a
label body as the end of that label, pushing the token back so the
caller can dispatch it as menu-level input. That is correct for
extlinux/pxelinux, where the only thing legitimately following a label
body is another 'label' (or a top-level 'menu ...') line.

Other formats that share enough syntax to reuse this parser have
different rules. The Boot Loader Specification, in particular, lists a
number of entry-level keys (title, version, sort-key, machine-id,
architecture, ...) that this parser knows nothing about, and the spec
explicitly requires implementations to silently ignore unrecognised
keys rather than treat them as a structural boundary.

Add an ignore_unknown flag to parse_label_keys(): when set, the default
switch case consumes the rest of the offending line via eol_or_eof()
and continues parsing instead of returning. The existing extlinux
caller passes false and so is unaffected.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
The parser already understands the "title" keyword at the menu level
(via "menu title"). Boot Loader Specification [1] type flipperdevices#2 entry files
use a bare "title" line at the entry level to give the human-readable
name of the entry, the closest extlinux equivalent of which is
"menu label" inside a label body.

Make parse_label_keys() honour "title" the same way it honours
"menu label", populating label->menu. This lets BLS entries surface
their pretty name through the existing label->menu plumbing without
the BLS bootmeth (or any other caller) having to special-case it.

No effect on existing extlinux/pxelinux files: those use "menu label"
inside a label, not bare "title", so this change is purely additive.

[1] https://uapi-group.org/specifications/specs/boot_loader_specification/

Signed-off-by: Alexey Charkov <alchark@flipper.net>
Add a bootmeth that finds and boots Boot Loader Specification (BLS)
type flipperdevices#1 entry files [1]. On each block-device partition it scans, the
bootmeth looks for files matching '<prefix>loader/entries/*.conf'
(where <prefix> comes from bootstd_get_prefixes(), typically '/' and
'/boot/'), picks the highest-sorting filename, parses it, and exposes
it as a bootflow.

Implementation reuses the existing pxelinux infrastructure.

For now the entry chosen on a partition is purely the lexicographic
maximum of *.conf filenames; sort-key / version field handling
(spec-mandated tiebreakers) and boot-counting (the '+TRIES_LEFT'
filename suffix) are left as TODOs. Likewise, only the top-sorted entry
is surfaced because the bootstd framework currently allows one bootflow
per (bootmeth, partition); exposing every discovered entry will require
a framework extension.

Type flipperdevices#2 BLS (drop-in directory of EFI binaries) is out of scope here;
existing EFI bootmeths cover that use case.

[1] https://uapi-group.org/specifications/specs/boot_loader_specification/

Signed-off-by: Alexey Charkov <alchark@flipper.net>
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Signed-off-by: Alexey Charkov <alchark@flipper.net>
alchark and others added 19 commits July 13, 2026 11:10
The key and description column x-offsets were previously fixed
proportions of the reference 1366-pixel design width (230 px and 280 px
respectively).  On displays narrower than ~350 px the scaled values are
smaller than the actual label text, causing the key and description
columns to overlap the label column.

Compute the offsets dynamically instead: after scene_menu_calc_dims()
has equalised all item widths, read the bounding-box widths of the
first item's label and key objects and derive:
  key_ofs  = label_ofs + label_col_w + gap
  desc_ofs = key_ofs   + key_col_w   + gap

Fall back to the reference-design proportional values when the menu has
no items.
bootflow_menu_new() set bounding boxes for the title, navigation hint
and help text using hardcoded pixel values derived from a specific font
height. Switching font (e.g. to 6x8) or running at different resolutions
could leave text clipped or pushed off-screen.

Add a char_h parameter to bootflow_menu_new().  When non-zero it is the
actual pixel height of one character cell, obtained from the vidconsole's
y_charsize field.  When zero (e.g. in unit tests without a live console)
the function falls back to max(SY(16), 1) so the layout remains sane.

Replace every magic pixel constant with a multiple of char_h:
  - title bbox y1:  max(SY(32) + SY(30), char_h)   -- at least one line
  - prompt1 y0:     min(SY(590), height - 6*char_h) -- 6 lines from bottom
  - prompt1 height: max(SY(30), 2*char_h)           -- fits 2 wrapped lines
  - prompt2 y0:     min(SY(650), height - 4*char_h) -- 4 lines from bottom

Also guard the U-Boot logo: skip it when the reserved right-side column
(scaled from the 1366 px reference) is narrower than 64 px, preventing
a clipped logo strip from bleeding over the menu box on small displays
such as the 256x144 Flipper One screen.

In bootflow_menu_setup(), obtain the vidconsole as a child of the video
device (mirroring expo_set_display()) and pass its y_charsize; fall back
to 0 if no console is found.

Update the unit test to pass 0 for char_h (reference-design default).
Signed-off-by: Alexey Charkov <alchark@flipper.net>
When exiting a graphical Expo menu, the console cursor is left indented
to the left edge of the last menu column, which wastes screen space and
looks awkward.

Reset the console when exiting the menu with e.g. Ctrl+C, so that the
console can resume normally from top-left of the screen.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
Label and description strings in each menu entry can be arbitrarily long,
but the menu box has a fixed width.

To avoid awkward layout issues when the screen is small and/or the strings
are overly long, limit the label width to 1/5 of the menu box width, and
the description width to 2/3 of the menu box width, truncating the excess.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
Signed-off-by: Alexey Charkov <alchark@flipper.net>
Video console is not usable with only the built-in buttons on the Flipper
One, so make sure the menu automatically restarts if closed, and the auto
boot timer only resets by a key not present on the Flipper One itself (s).

Signed-off-by: Alexey Charkov <alchark@flipper.net>
Existing prompts in the bootflow menu appear to have been copied verbatim
from GRUB, and current U-boot code doesn't implement the functionality
implied by the wording (edit arguments, drop to console, autoboot).

Remove the misleading wording from the prompts, which also makes them
short enough to fit below the menu box for a cleaner layout.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
Remove options not absolutely required for regular on-device booting to
reduce the U-Boot startup time

Signed-off-by: Alexey Charkov <alchark@flipper.net>
The pinctrl driver has to scan over 200 subnodes of its DT node, and this
takes ~0.6s with the D-cache off in board_init_f.

Given that the SPL has already muxed the console and PMIC pins, there is
no urgency to bind pinctrl in board_init_f. Instead, defer the binding to
board_init_r, which takes ~13ms with the D-cache on.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
Current code tries to print information about the reset method whenever
sysreset support is enabled. This causes the core to try to bind the
sysreset device in board_init_f, even if the driver doesn't support
reset status reporting, causing pure waste on some platforms (e.g. on
Rockchip RK3576 it increases the boot time by ~0.4s even though the driver
doesn't support reset status reporting).

Make the printing of reset information optional, so that it can be
enabled only on platforms where it is supported and useful.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
To interrupt boot, press and hold 's' in the serial console while powering
on.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
The calculation in rockchip_rk3588_pll_k_get() uses an intermediate
variable misleadingly named fout, which is not the output frequency.

Drop it and inline its calculation into the k assignment, which also
improves clarity. While at that, also drop the redundant reassignment of
fref which doesn't change within this function.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
Current code uses magical constants when rounding up the magnitude of
negative fractional PLL component k. This leads to overshooting the
requested rate when the calculated fractional part has less than 0.3 in
its decimal part due to failure to round up the fractional part.

Use a proper rounding up function to avoid overshooting the requested
rate and make the calculation more readable.

Fixes: 6bfb37e ("clk: rockchip: rk3588: fix up the frac pll calculation")
Signed-off-by: Alexey Charkov <alchark@flipper.net>
Current code needlessly sets the k value to 0 when it is calculated as
-32768, which is a valid value for the RK3588 frac PLL. This results in
the PLL output frequency being higher than requested when the requested
frequency is exactly halfway between two integer-multiplier PLL output
frequencies.

Negative k values can never go below -32768 either, because that case is
handled just above this code, so the check for k > 32767 is redundant.

What remains of the if statement is a hand-rolled two's complement
negation of the result, so write it out as such for clarity, and return
the true S16 type of k as specified in the TRM.

Fixes: 6bfb37e ("clk: rockchip: rk3588: fix up the frac pll calculation")
Signed-off-by: Alexey Charkov <alchark@flipper.net>
Selecting the next integer multiplier m is coupled to setting a negative
fractional coefficient k. The current code checks for negative k in two
separate places, which is error-prone.

Let rockchip_rk3588_pll_k_get update m directly, to make it the single
source of truth for the final value of the integer multiplier m, which
also reduces the number of scattered conditional branches in the code.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
The TRM defines the fractional PLL adjustment coefficient as a signed
two's complement number, 16 bits wide, so store it as such to avoid
confusion.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
…rk3588_pll_get_rate

Current code calculates the fractional component in 32 bits before
assigning it to a 64-bit holding variable, causing overflow for real-world
values of k, given that OSC_HZ is 24000000U. It also does bitwise manual
massaging of an unsigned representation of what is actually a two's
complement signed value, which is confusing and makes the code harder to
read.

Read k into a properly signed type and promote operands to avoid overflow,
which also enables the use of div_s64() to express the math more clearly.

Fixes: b851c00 ("clk: rockchip: pll: Add pll_rk3588 type for rk3588")
Signed-off-by: Alexey Charkov <alchark@flipper.net>
Update the zstd implementation to match Linux v6.15's lib/zstd, which
imports upstream zstd 1.5.7 in Linux commit 65d1f5507ed2 ("zstd: Import
upstream v1.5.7") and includes the follow-up workaround from Linux
commit 1400c87e6cac ("zstd: Increase DYNAMIC_BMI2 GCC version cutoff
from 4.8 to 11.0 to work around compiler segfault").

As with the previous 1.5.2 import (commit 4b9b25d), this is a
straight mirror of the Linux zstd code, except to:
- update a few #include that do not translate cleanly
  - linux/unaligned.h -> asm/unaligned.h (Linux moved this header in
    commit 5f60d5f6bbc1)
  - linux/swab.h -> asm/byteorder.h
  - linux/limits.h -> linux/kernel.h
  - linux/module.h -> linux/compat.h
- remove assert() from debug.h so it doesn't conflict with u-boot's
  assert()
- strip out the compressor code as was done in the previous u-boot zstd
- change the #define for MEM_STATIC to use INLINE_KEYWORD/UNUSED_ATTR
  for codesize
- drop ZSTD_SRCSIZEHINT_MAX (needs INT_MAX from linux/limits.h) as was
  done in the previous import
- collapse consecutive blank lines to keep checkpatch happy

New files in this sync: lib/zstd/common/allocations.h and
lib/zstd/common/bits.h. The decompress-only object list in
lib/zstd/Makefile and the CONFIG_ZSTD_LIB_MINIFY ccflags are unchanged
from the 1.5.2 import. The kernel-style wrapper API in
include/linux/zstd.h is source-compatible, so lib/zstd/zstd.c and
fs/squashfs/sqfs_decompressor.c need no changes.

Tested with:
- clean builds of sandbox, sandbox64, am62x_evm_a53 (aarch64) and
  sandbox with ZSTD_LIB_MINIFY=n
- ut lib compression_test_zstd and compression_test_bootm_zstd: pass
- imxtract of a FIT subimage compressed with upstream zstd 1.5.7
  (python-zstandard), decompressed output crc32-verified against the
  original payload
- sqfsload of a file from a zstd-compressed squashfs, crc32-verified
- Real hardware: RAM-booted this branch on an Orange Pi 5B (RK3588S)
  via maskrom/USB, loaded a zstd-1.5.7-compressed FIT payload from a
  USB stick with imxtract, CRC32 matched.

Signed-off-by: Inhertz <huesostorres2@hotmail.com>
@Inhertz
Inhertz requested a review from a team July 21, 2026 06:57
@alchark

alchark commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Hi @Inhertz, thanks a lot for your contribution! This is massive, and much appreciated!

Several things jump to my mind as I'm looking at this:

  1. Your signoff line should include your full name per U-Boot rules - this is an actual legal requirement for upstream contributions. Please have a look at https://github.com/u-boot/u-boot/blob/main/doc/develop/process.rst and the related docs
  2. As this is a rather big change, maintainers would likely be reluctant to jump on it unless there is a meaningful demonstrable improvement (bugs fixed and/or performance improved). So it would be great if you could start by adding test cases (in separate commits before the import itself) which should work, but fail using the current code, and get fixed by the import
  3. The change itself is well described and I believe it is correct, but to go from beliefs to hard facts it would be great if your cover letter included an actual diff of the changes vs. the current Linux version which were required to make it fit for U-Boot, along with a case by case indication of whether similar differences exist in the current codebase vs. its respective Linux kernel sibling from the olden days

It's best to submit such a change directly to the upstream mailing list where it can be reviewed and applied. Once you feel comfortable doing so, please rebase on top of the main branch and use b4 to send out your git commits as plaintext emails. Happy to help you out with the process if needed!

Meanwhile, we'll try and test this with our workloads on RK3576 :)

@Yury-MonZon

Yury-MonZon commented Jul 21, 2026

Copy link
Copy Markdown

Nice work! Tested this on real hardware (RK3576, Flipper One) and it fixes a real boot bug for us.
Dropping the logs here in case they're useful as an upstream validation case.

Our rootfs is btrfs with compress=zstd, and U-Boot boots via bls, reading the kernel,
DTB, DT overlays and loader entries straight off btrfs. With the old 1.5.2 zstd, U-Boot could
not decompress small files that btrfs stores as inline extents (those go through a separate
inline decode path). Larger files stored as regular compressed extents (like the ~40K DTB) read
fine, so it only bit the small ones:

zstd_decompress: failed to decompress: 70
BTRFS: An error occurred while reading file ...

In our boot set the inline ones are the small .dtbo overlays and the BLS loader entries, so we
had been forcing the boot set uncompressed to dodge it. With your 1.5.7 the inline decode works:
the compressed .dtbo overlay (268B on disk) and the compressed loader entry (332B) read, the
overlay applies, and the board boots a fully compressed boot set:

Selected: No Graphics 7.2.0-rc3-g4e4

** Booting bootflow 'ufs_scsi.id0lun0.bootdev.part_3.8' with bls
:	No Graphics 7.2.0-rc3-g4e4
Retrieving file: /@No-Graphics/usr/lib/modules/7.2.0-rc3-g4e490ee42221/vmlinuz
Retrieving file: /@No-Graphics/usr/lib/modules/7.2.0-rc3-g4e490ee42221/initrd
append: root=UUID=967eb119-29d5-4f18-a8ab-af0ce127a1ba audit=0 console=tty1 console=ttyS0,1500000n8 console=ttyS4,1500000n8 fbcon=map:1 rootflags=subvol=@No-Graphics
Retrieving file: /@No-Graphics/usr/lib/linux-image-7.2.0-rc3-g4e490ee42221/rockchip/rk3576-flipper-one-rev-f0b0c1.dtb
Retrieving file: /@No-Graphics/usr/lib/linux-image-7.2.0-rc3-g4e490ee42221/rockchip/rk3576-no-graphics.dtbo
   Uncompressing Kernel Image to 0
## Flattened Device Tree blob at 52000000
   Booting using the fdt blob at 0x52000000
Working FDT set to 52000000
   Loading Ramdisk to fc133000, end fcbff09c ... OK
   Loading Device Tree to 00000000fcd47000, end 00000000fcd7dfff ... OK
Working FDT set to fcd47000

Starting kernel ...

The no-graphics overlay disables VOP/HDMI/GPU and the board came up headless, so it was read
and applied, not just read.

Those files really are zstd on disk (btrfs compsize). The DTB is a regular extent (read fine even
before); the overlay and loader entry are the small inline ones that were broken:

rk3576-flipper-one-rev-f0b0c1.dtb   TOTAL  20%   40K / 200K
rk3576-no-graphics.dtbo             TOTAL  24%  268B / 1.0K
500-...-No-Graphics-....conf (BLS)  TOTAL  51%  332B / 642B

And a fresh write compresses transparently (rename + copy back, no reflink), so kernel installs
just work with no manual uncompress step:

Processed 1 file, 2 regular extents (2 refs), 0 inline.
TOTAL  20%   40K / 200K
zstd   20%   40K / 200K
encoded extents: 2

Binary under test:

U-Boot 2026.07-g25875f4275c7 (Jul 21 2026 - 09:03:52 +0100)

25875f4275c7 is your head 7ad4e2c merged onto our base, so it's exactly this PR.

@munzzyy

munzzyy commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

I didn't try to review vendored zstd line by line, but I did check the one thing that decides
whether this is reviewable at all: whether it's actually a faithful mirror. It is.

I pulled the 31 files this commit touches from Linux v6.15 and diffed them against the branch:

while read -r f; do
    curl -sfL --create-dirs -o "/tmp/l615/$f" \
         "https://raw.githubusercontent.com/torvalds/linux/v6.15/$f"
    diff -u "/tmp/l615/$f" "$f"
done < <(git show --name-only --pretty= HEAD)

27 of the 31 differ, but 20 of those differ only by removed blank lines, which is the checkpatch
pass you mention. That leaves 7 files and 32 changed lines of actual content, and every one is
something you already listed: the include swaps in mem.h and zstd_deps.h, module.h -> compat.h
in the two module files, the assert block dropped from debug.h, MEM_STATIC in mem.h,
ZSTD_SRCSIZEHINT_MAX dropped from zstd_lib.h. include/linux/zstd.h also keeps u-boot's
int zstd_decompress(struct abuf *, struct abuf *), carried over from the 1.5.2 import.

The decompressor itself is untouched. huf_decompress.c, zstd_decompress.c,
zstd_decompress_block.c, zstd_errors.h and the rest of common/ have zero code changes against
v6.15 - blank lines only. That's the hard-facts version of alchark's point 3, and those seven
files are short enough to paste into the cover letter as-is.

The other thing is @Yury-MonZon's report above, and I want to flag it before it becomes the
reason this lands. I don't think the zstd bump is what fixed their btrfs inline reads.

Error 70 is dstSize_tooSmall, and in the one-shot path it means the destination was smaller
than the frame's declared content size. The checks that produce it are unchanged across the
two imports. zstd_decompress_block.c:158 and :191 here are

size_t expectedWriteSize = MIN(blockSizeMax, dstCapacity);
...
RETURN_ERROR_IF(expectedWriteSize < litSize , dstSize_tooSmall, "");

against 1.5.2's line 141 and 167, which are the same two lines with ZSTD_BLOCKSIZE_MAX instead
of blockSizeMax. The sequence-tail checks match too. And upstream 1.5.7 still refuses in
practice - I compressed 4096 bytes shaped like a compressed inline extent (1900 bytes of text,
then zero fill past EOF, which is what the kernel hands zstd) and decompressed one-shot:

frame: 83 bytes, declared content size 4096
dst = ram_bytes (1900) -> Destination buffer is too small (code 70)
dst = blocksize (4096) -> OK, 4096 bytes out

u-boot sizes that destination from ram_bytes - fs/btrfs/inode.c:382-384, dsize = btrfs_file_extent_ram_bytes() then malloc(dsize) - so a kernel-written inline extent still
fails on this branch as far as I can tell.

Disclosure: I have a patch for that on the u-boot list and in #38, so I'm not a neutral party
here, which is why I'd rather it got checked than taken on my word.

@Yury-MonZon, the cheap way to settle it is to run your old binary and this one against the same
untouched filesystem, no rewrites in between. Your log mentions a rename-and-copy-back step,
and that rewrites the extents, so the before and after may not be the same bytes on disk. If you
want to go further, the extent item for the overlay tells you which case it is:

ino=$(stat -c %i /path/to/rk3576-no-graphics.dtbo)
btrfs inspect-internal dump-tree -t <subvol tree id> /dev/... | grep -A2 "($ino EXTENT_DATA"
#    generation 6 type 0 (inline)
#    inline extent data size 402 ram_bytes 1900 compression 3 (zstd) encryption 0

If it's still inline and zstd, pull those bytes out and run zstd -l on them. Declared size
above ram_bytes means it should still fail here, and something other than the bump changed
between your two boots. Declared size equal to ram_bytes means the file came from btrfs-progs
rather than the kernel write path, and neither this PR nor my patch is involved. I could easily
be missing something - if it really does read with the frame declaring more than ram_bytes, I
want to know, because that contradicts what I measured.

Smaller thing: zstd_decompress_module.c picks up five wrappers from Linux -
zstd_create_dctx_advanced, zstd_free_dctx, zstd_create_ddict_byreference, zstd_free_ddict,
zstd_decompress_using_ddict - and nothing in u-boot calls them; grep only finds the definitions
and the prototypes in zstd.h. Keeping them makes the next resync a straight copy, which seems
like the right call, but you'll probably get asked on the list.

@alchark
alchark force-pushed the rk3576 branch 2 times, most recently from 1f5af61 to 761c654 Compare August 26, 2026 16:36
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.

Bundle a newer zstd (currently 1.5.2)

6 participants