rockchip: add support for PX30 Ringneck SoM on Haikou Devkit
The PX30-µQ7 (Ringneck) is a system-on-module featuring the Rockchip
PX30 in a micro Qseven-compatible form-factor.
PX30-µQ7 features:
* CPU: quad-core Cortex-A35
* DRAM: 2GB dual-channel
* eMMC: onboard eMMC
* SD/MMC
* TI DP83825I 10/100Mbps PHY
* USB:
* USB2.0 dual role port
* 3x USB2.0 host via onboard USB2.0 hub
* Display: MIPI-DSI
* Camera: MIPI-CSI
* onboard 2.4GHz WiFi + Bluetooth module
* Companion Controller: on-board additional microcontroller
(STM32 Cortex-M0 or ATtiny):
* RTC
* fan controller
* CAN (only STM32)
The non-U-Boot DTS files are imported from Linux v6.2-rc2.
Cc: Quentin Schulz <foss+uboot@0leil.net>
Reviewed-by: Kever Yang <kever.yang@rock-chips.com>
Signed-off-by: Quentin Schulz <quentin.schulz@theobroma-systems.com>
diff --git a/board/theobroma-systems/ringneck_px30/Kconfig b/board/theobroma-systems/ringneck_px30/Kconfig
new file mode 100644
index 0000000..24d9480
--- /dev/null
+++ b/board/theobroma-systems/ringneck_px30/Kconfig
@@ -0,0 +1,18 @@
+if TARGET_RINGNECK_PX30
+
+config SYS_BOARD
+ default "ringneck_px30"
+
+config SYS_VENDOR
+ default "theobroma-systems"
+
+config SYS_CONFIG_NAME
+ default "ringneck_px30"
+
+config BOARD_SPECIFIC_OPTIONS # dummy
+ def_bool y
+
+config ENV_SIZE
+ default 0x3000
+
+endif
diff --git a/board/theobroma-systems/ringneck_px30/MAINTAINERS b/board/theobroma-systems/ringneck_px30/MAINTAINERS
new file mode 100644
index 0000000..d764e26
--- /dev/null
+++ b/board/theobroma-systems/ringneck_px30/MAINTAINERS
@@ -0,0 +1,9 @@
+RINGNECK-PX30
+M: Quentin Schulz <quentin.schulz@theobroma-systems.com>
+M: Klaus Goger <klaus.goger@theobroma-systems.com>
+S: Maintained
+F: board/theobroma-systems/ringneck_px30
+F: include/configs/ringneck_px30.h
+F: arch/arm/dts/px30-ringneck*
+F: configs/ringneck-px30_defconfig
+W: https://www.theobroma-systems.com/px30-uq7#tech-spec
diff --git a/board/theobroma-systems/ringneck_px30/Makefile b/board/theobroma-systems/ringneck_px30/Makefile
new file mode 100644
index 0000000..31ada1a
--- /dev/null
+++ b/board/theobroma-systems/ringneck_px30/Makefile
@@ -0,0 +1,7 @@
+#
+# (C) Copyright 2022 Theobroma Systems Design und Consulting GmbH
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-y += ringneck-px30.o
diff --git a/board/theobroma-systems/ringneck_px30/README b/board/theobroma-systems/ringneck_px30/README
new file mode 100644
index 0000000..e756b3a
--- /dev/null
+++ b/board/theobroma-systems/ringneck_px30/README
@@ -0,0 +1,69 @@
+Introduction
+============
+
+The PX30-uQ7 (Ringneck) SoM is a µQseven-compatible (40mmx70mm, MXM-230
+connector) system-on-module from Theobroma Systems[1], featuring the
+Rockchip PX30.
+
+It provides the following feature set:
+ * up to 4GB DDR4
+ * up to 128GB on-module eMMC (with 8-bit 1.8V interface)
+ * SD card (on a baseboard) via edge connector
+ * Fast Ethernet with on-module TI DP83825I PHY
+ * MIPI-DSI/LVDS
+ * MIPI-CSI
+ * USB
+ - 1x USB 2.0 dual-role
+ - 3x USB 2.0 host
+ * on-module companion controller (STM32 Cortex-M0 or ATtiny), implementing:
+ - low-power RTC functionality (ISL1208 emulation)
+ - fan controller (AMC6821 emulation)
+ - USB<->CAN bridge controller (STM32 only)
+ * on-module Espressif ESP32 for Bluetooth + 2.4GHz WiFi
+ * on-module NXP SE05x Secure Element
+
+Here is the step-by-step to boot to U-Boot on px30.
+
+Get the Source and build ATF binary
+===================================
+
+ > git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
+
+Compile the ATF
+===============
+
+ > cd trusted-firmware-a
+ > make CROSS_COMPILE=aarch64-linux-gnu- PLAT=px30 bl31
+ > cp build/px30/release/bl31/bl31.elf ../u-boot/bl31.elf
+
+Compile the U-Boot
+==================
+
+ > cd ../u-boot
+ > make CROSS_COMPILE=aarch64-linux-gnu- ringneck-px30_defconfig all
+
+Flash the image
+===============
+
+Copy u-boot-rockchip.bin to offset 32k for SD/eMMC.
+
+SD-Card
+-------
+
+ > dd if=u-boot-rockchip.bin of=/dev/sdb seek=64
+
+eMMC
+----
+
+rkdeveloptool allows to flash the on-board eMMC via the USB OTG interface with
+help of the Rockchip loader binary.
+
+ > git clone https://github.com/rockchip-linux/rkdeveloptool
+ > cd rkdeveloptool
+ > autoreconf -i && ./configure && make
+ > git clone https://github.com/rockchip-linux/rkbin.git
+ > cd rkbin
+ > ./tools/boot_merger RKBOOT/PX30MINIALL.ini
+ > cd ..
+ > ./rkdeveloptool db rkbin/px30_loader_v1.16.131.bin
+ > ./rkdeveloptool wl 64 ../u-boot-rockchip.bin
diff --git a/board/theobroma-systems/ringneck_px30/ringneck-px30.c b/board/theobroma-systems/ringneck_px30/ringneck-px30.c
new file mode 100644
index 0000000..47d1a40
--- /dev/null
+++ b/board/theobroma-systems/ringneck_px30/ringneck-px30.c
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2022 Theobroma Systems Design und Consulting GmbH
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <env.h>
+#include <env_internal.h>
+#include <init.h>
+#include <log.h>
+#include <misc.h>
+#include <spl.h>
+#include <syscon.h>
+#include <u-boot/crc.h>
+#include <usb.h>
+#include <dm/pinctrl.h>
+#include <dm/uclass-internal.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <asm/arch-rockchip/periph.h>
+#include <asm/arch-rockchip/misc.h>
+#include <power/regulator.h>
+#include <u-boot/sha256.h>
+
+/*
+ * Swap mmc0 and mmc1 in boot_targets if booted from SD-Card.
+ *
+ * If bootsource is uSD-card we can assume that we want to use the
+ * SD-Card instead of the eMMC as first boot_target for distroboot.
+ * We only want to swap the defaults and not any custom environment a
+ * user has set. We exit early if a changed boot_targets environment
+ * is detected.
+ */
+static int setup_boottargets(void)
+{
+ const char *boot_device =
+ ofnode_read_chosen_string("u-boot,spl-boot-device");
+ char *env_default, *env;
+
+ if (!boot_device) {
+ debug("%s: /chosen/u-boot,spl-boot-device not set\n",
+ __func__);
+ return -1;
+ }
+ debug("%s: booted from %s\n", __func__, boot_device);
+
+ env_default = env_get_default("boot_targets");
+ env = env_get("boot_targets");
+ if (!env) {
+ debug("%s: boot_targets does not exist\n", __func__);
+ return -1;
+ }
+ debug("%s: boot_targets current: %s - default: %s\n",
+ __func__, env, env_default);
+
+ if (strcmp(env_default, env) != 0) {
+ debug("%s: boot_targets not default, don't change it\n",
+ __func__);
+ return 0;
+ }
+
+ /*
+ * Make the default boot medium between SD Card and eMMC, the one that
+ * was used to load U-Boot proper.
+ */
+ bool sd_booted = !strcmp(boot_device, "/mmc@ff370000");
+ char *mmc0, *mmc1;
+
+ debug("%s: booted from %s\n", __func__,
+ sd_booted ? "SD-Card" : "eMMC");
+ mmc0 = strstr(env, "mmc0");
+ mmc1 = strstr(env, "mmc1");
+
+ if (!mmc0 || !mmc1) {
+ debug("%s: only one mmc boot_target found\n", __func__);
+ return -1;
+ }
+
+ /*
+ * If mmc0 comes first in the boot order and U-Boot proper was
+ * loaded from mmc1, swap mmc0 and mmc1 in the list.
+ * If mmc1 comes first in the boot order and U-Boot proper was
+ * loaded from mmc0, swap mmc0 and mmc1 in the list.
+ */
+ if ((mmc0 < mmc1 && sd_booted) ||
+ (mmc0 > mmc1 && !sd_booted)) {
+ mmc0[3] = '1';
+ mmc1[3] = '0';
+ debug("%s: set boot_targets to: %s\n", __func__, env);
+ env_set("boot_targets", env);
+ }
+
+ return 0;
+}
+
+int mmc_get_env_dev(void)
+{
+ const char *boot_device =
+ ofnode_read_chosen_string("u-boot,spl-boot-device");
+
+ if (!boot_device) {
+ debug("%s: /chosen/u-boot,spl-boot-device not set\n",
+ __func__);
+ return CONFIG_SYS_MMC_ENV_DEV;
+ }
+
+ debug("%s: booted from %s\n", __func__, boot_device);
+
+ if (!strcmp(boot_device, "/mmc@ff370000"))
+ return 1;
+
+ if (!strcmp(boot_device, "/mmc@ff390000"))
+ return 0;
+
+ return CONFIG_SYS_MMC_ENV_DEV;
+}
+
+#if !IS_ENABLED(CONFIG_ENV_IS_NOWHERE)
+#error Please enable CONFIG_ENV_IS_NOWHERE
+#endif
+
+enum env_location arch_env_get_location(enum env_operation op, int prio)
+{
+ const char *boot_device =
+ ofnode_read_chosen_string("u-boot,spl-boot-device");
+
+ if (prio > 0)
+ return ENVL_UNKNOWN;
+
+ if (!boot_device) {
+ debug("%s: /chosen/u-boot,spl-boot-device not set\n",
+ __func__);
+ return ENVL_NOWHERE;
+ }
+
+ debug("%s: booted from %s\n", __func__, boot_device);
+
+ if (IS_ENABLED(CONFIG_ENV_IS_IN_MMC) &&
+ (!strcmp(boot_device, "/mmc@ff370000") ||
+ !strcmp(boot_device, "/mmc@ff390000")))
+ return ENVL_MMC;
+
+ printf("%s: No environment available: booted from %s but U-Boot "
+ "config does not allow loading environment from it.",
+ __func__, boot_device);
+
+ return ENVL_NOWHERE;
+}
+
+int misc_init_r(void)
+{
+ const u32 cpuid_offset = 0x7;
+ const u32 cpuid_length = 0x10;
+ u8 cpuid[cpuid_length];
+ int ret;
+
+ ret = rockchip_cpuid_from_efuse(cpuid_offset, cpuid_length, cpuid);
+ if (ret)
+ return ret;
+
+ ret = rockchip_cpuid_set(cpuid, cpuid_length);
+ if (ret)
+ return ret;
+
+ ret = rockchip_setup_macaddr();
+ if (ret)
+ return ret;
+
+ setup_boottargets();
+
+ return 0;
+}