[PATCH v2] arm64: rockchip: Add support for QNAP's ts-433 4bay NAS

Ahmad Fatoum a.fatoum at pengutronix.de
Tue Jul 22 09:42:39 PDT 2025


Hello Uwe,

On 7/19/25 19:47, Uwe Kleine-König wrote:
> The resulting image boots to a prompt using usb booting or when booting
> from eMMC. Networking and USB are working.

Cool stuff!

My comments below.

> Thanks to the fine rk3568 base support this was an easy journey to
> create a powerful bootloader for my NAS. Thanks!

Glad to hear. :)

> diff --git a/arch/arm/boards/qnap-tsx33/board.c b/arch/arm/boards/qnap-tsx33/board.c
> new file mode 100644
> index 000000000000..2611f7a6a9bf
> --- /dev/null
> +++ b/arch/arm/boards/qnap-tsx33/board.c
> @@ -0,0 +1,73 @@
> +#include <common.h>
> +#include <gpio.h>
> +#include <init.h>
> +#include <mach/rockchip/bbu.h>
> +#include <bootsource.h>
> +#include <environment.h>
> +#include <globalvar.h>
> +#include <magicvar.h>
> +#include <deep-probe.h>
> +
> +static int ts433_usb_device_mode(void)
> +{
> +	struct device_node *node;
> +
> +	/* &usb_host0_xhci */
> +	node = of_find_node_by_path("/usb at fcc00000");
> +	if (!node)
> +		return -ENODEV;
> +
> +	return of_property_write_string(node, "dr_mode", "peripheral");
> +}
> +
> +static int ts433_probe(struct device *dev)
> +{
> +	enum bootsource bootsource = bootsource_get();
> +	int copy_button_pressed = !gpio_get_value(14);

You need to ensure the GPIO controller is probed before you try to get
the GPIO, e.g. by calling

  of_devices_ensure_probed_by_property("gpio-controller");

first.

My preference would be using the input API for this though.

Define a gpio-keys node in the DT, wire the GPIO and then call:

  of_devices_ensure_probed_by_compatible("gpio-keys");
  input_key_get_status(keys, KEY_COPY);

For an example, see commit e44d472d128d ("ARM: boards: protonic-imx6:
prtvt7: Use the input system for key detection").


> +	barebox_set_model("QNAP TS-433");
> +	barebox_set_hostname("ts433");
> +
> +	if (bootsource == BOOTSOURCE_USB || copy_button_pressed) {
> +		/*
> +		 * Configure the front USB socket to USB device (i.e. like the
> +		 * ROM when booting from USB. Add gadget support equivalent to
> +		 * usbgadget -b -A "kernel(kernel)c,initramfs(initramfs)c,dtb(dtb)" -a
> +		 */
> +		ts433_usb_device_mode();

If you set dr_mode = "otg" in the device tree, you can just do
otg.mode=peripheral/host in barebox without having to mess with DT directly.

> +		globalvar_add_simple("usbgadget.autostart", "1");

Conceptually, this should be at the end, because it activate the
feature. It doesn't matter here though, I think, because it's only
evaluated later on.

> +		globalvar_add_simple("fastboot.bbu", "1");
> +		globalvar_add_simple("fastboot.partitions", "kernel(kernel)c,initramfs(initramfs)c,dtb(dtb)c");
> +		globalvar_add_simple("usbgadget.acm", "1");

These could have been a built-in init script, but both are fine I guess.

> +		/*
> +		 * exit to a shell, also to give the user the chance to open the
> +		 * console on USB.
> +		 */
> +		globalvar_add_simple("autoboot", "abort");

You could instead set a higher count down time, so a mistaken press
during startup will eventually boot still. For actual flashing use,
first fastboot command or console input will abort the countdown anyway.

> +
> +		/*
> +		 * Don't use emmc to result in a working state even with a
> +		 * borked environment.
> +		 */
> +		of_device_disable_path("/chosen/environment-emmc");

You will want to call globalvar_set("env.autoprobe", "0") as well, so
environment isn't autoprobed by Type UUID.

Cheers,
Ahmad

> +	}
> +
> +	rockchip_bbu_mmc_register("emmc", BBU_HANDLER_FLAG_DEFAULT, "/dev/mmc0");
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id ts433_of_match[] = {
> +        { .compatible = "qnap,ts433" },
> +        { /* Sentinel */},
> +};
> +
> +static struct driver ts433_board_driver = {
> +        .name = "board-ts433",
> +        .probe = ts433_probe,
> +        .of_compatible = ts433_of_match,
> +};
> +coredevice_platform_driver(ts433_board_driver);
> +
> +BAREBOX_DEEP_PROBE_ENABLE(ts433_of_match);
> diff --git a/arch/arm/boards/qnap-tsx33/lowlevel.c b/arch/arm/boards/qnap-tsx33/lowlevel.c
> new file mode 100644
> index 000000000000..f852e8d00a2b


> --- /dev/null
> +++ b/arch/arm/dts/rk3568-qnap-ts433.dts
> @@ -0,0 +1,26 @@
> +// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
> +
> +/dts-v1/;
> +#include <arm64/rockchip/rk3568-qnap-ts433.dts>
> +#include "rk356x.dtsi"
> +
> +/ {
> +	chosen: chosen {
> +		environment-emmc {
> +			compatible = "barebox,environment";
> +			device-path = &sdhci, "partname:barebox-environment";
> +		};
> +	};

If you choose 6C3737F2-07F8-45D1-AD45-15D260AAB24D as GPT partition type
UUID, barebox should automatically choose it as environment partition.

This would allow you to drop this node completely.

> +};
> +
> +&gmac0 {
> +	/*
> +	 * The Linux device tree uses rgmii-id and that also works iff the
> +	 * matching phy driver (motorcomm) is available. The barebox motorcomm
> +	 * driver however doesn't support the used phy (Motorcomm YT8521) yet
> +	 * and so we have to stick to rgmii and explicit delays for now.
> +	 */

Fair enough.

> +	phy-mode = "rgmii";
> +	tx_delay = <0x3c>;
> +	rx_delay = <0x2f>;
> +};

Cheers,
Ahmad

-- 
Pengutronix e.K.                  |                             |
Steuerwalder Str. 21              | http://www.pengutronix.de/  |
31137 Hildesheim, Germany         | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686  | Fax:   +49-5121-206917-5555 |




More information about the barebox mailing list