Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 32 additions & 4 deletions config/boards/radxa-e52c.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ BOARD_VENDOR="radxa"
BOARDFAMILY="rockchip-rk3588"
BOARD_MAINTAINER="amazingfate schwar3kat"
BOOTCONFIG="radxa-e52c-rk3588s_defconfig"
KERNEL_TARGET="vendor"
KERNEL_TARGET="vendor,current,edge"
BOOT_FDT_FILE="rockchip/rk3588s-radxa-e52c.dtb"
BOOT_SCENARIO="spl-blobs"
BOOT_SOC="rk3588"
DEFAULT_CONSOLE="serial"
IMAGE_PARTITION_TABLE="gpt"
HAS_VIDEO_OUTPUT="no"

Expand All @@ -22,7 +23,7 @@ function post_family_tweaks_bsp__radxa_e52c_enable_leds() {
tx=0
rx=1
device_name=lan

[/sys/class/leds/wan-led]
trigger=netdev
interval=52
Expand All @@ -31,11 +32,11 @@ function post_family_tweaks_bsp__radxa_e52c_enable_leds() {
tx=0
rx=1
device_name=wan

[/sys/class/leds/mmc0::]
trigger=mmc0
brightness=0

[/sys/class/leds/sys-led]
trigger=heartbeat
brightness=0
Expand All @@ -52,3 +53,30 @@ function post_family_tweaks_bsp__radxa_e52c_enable_leds() {
EOF
}

# Mainline U-Boot, only for non-vendor BRANCH
function post_family_config__radxa_e52c_use_mainline_uboot() {
[[ "${BRANCH}" == "vendor" ]] && return 0

declare -g BOOT_FDT_FILE="rockchip/rk3582-radxa-e52c.dtb"
display_alert "$BOARD" "u-boot ${BOOTBRANCH_BOARD} overrides" "info"
declare -g BOOTCONFIG="radxa-e52c-rk3582_defconfig"
declare -g BOOTSOURCE="https://github.com/u-boot/u-boot.git"
declare -g BOOTBRANCH="tag:v2026.01"
declare -g BOOTPATCHDIR="v2026.01"
declare -g BOOTDIR="u-boot-${BOARD}"
declare -g UBOOT_TARGET_MAP="BL31=${RKBIN_DIR}/${BL31_BLOB} ROCKCHIP_TPL=${RKBIN_DIR}/${DDR_BLOB};;u-boot-rockchip.bin"
unset uboot_custom_postprocess write_uboot_platform write_uboot_platform_mtd # disable stuff from rockchip64_common; we're using binman here which does all the work already

# Just use the binman-provided u-boot-rockchip.bin, which is ready-to-go
function write_uboot_platform() {
dd "if=$1/u-boot-rockchip.bin" "of=$2" bs=32k seek=1 conv=notrunc status=none
}
}

# Mainline U-Boot, only for non-vendor BRANCH
function post_config_uboot_target__extra_configs_for_radxa_e52c_mainline_uboot() {
[[ "${BRANCH}" == "vendor" ]] && return 0

display_alert "u-boot for ${BOARD}/${BRANCH}" "u-boot: enable BTRFS filesystem support" "info"
run_host_command_logged scripts/config --enable CONFIG_CMD_BTRFS
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <[email protected]>
Date: Wed, 7 Jan 2026 23:07:39 +0000
Subject: rockchip: Add initial RK3582 support

The RK3582 SoC is a variant of the RK3588S with some IP blocks disabled.
What blocks are disabled/non-working is indicated by ip-state in OTP.

This add initial support for RK3582 by using ft_system_setup() to mark
any cpu, gpu and/or vdec/venc node with status=fail as indicated by
ip-state.

This apply same policy as vendor U-Boot for RK3582, i.e. two big cpu
cores, the gpu and one vdec/venc core is always failed/disabled.

Enable Kconfig option OF_SYSTEM_SETUP in board defconfig to make use of
the required DT fixups for RK3582 board variants.

Signed-off-by: Jonas Karlman <[email protected]>
---
arch/arm/mach-rockchip/rk3588/rk3588.c | 215 ++++++++++
1 file changed, 215 insertions(+)

diff --git a/arch/arm/mach-rockchip/rk3588/rk3588.c b/arch/arm/mach-rockchip/rk3588/rk3588.c
index 111111111111..222222222222 100644
--- a/arch/arm/mach-rockchip/rk3588/rk3588.c
+++ b/arch/arm/mach-rockchip/rk3588/rk3588.c
@@ -7,6 +7,7 @@
#define LOG_CATEGORY LOGC_ARCH

#include <dm.h>
+#include <fdt_support.h>
#include <misc.h>
#include <spl.h>
#include <asm/armv8/mmu.h>
@@ -213,6 +214,16 @@ int arch_cpu_init(void)

#define RK3588_OTP_CPU_CODE_OFFSET 0x02
#define RK3588_OTP_SPECIFICATION_OFFSET 0x06
+#define RK3588_OTP_IP_STATE_OFFSET 0x1d
+
+#define FAIL_CPU_CLUSTER0 GENMASK(3, 0)
+#define FAIL_CPU_CLUSTER1 GENMASK(5, 4)
+#define FAIL_CPU_CLUSTER2 GENMASK(7, 6)
+#define FAIL_GPU GENMASK(4, 1)
+#define FAIL_RKVDEC0 BIT(6)
+#define FAIL_RKVDEC1 BIT(7)
+#define FAIL_RKVENC0 BIT(0)
+#define FAIL_RKVENC1 BIT(2)

int checkboard(void)
{
@@ -258,3 +269,207 @@ int checkboard(void)

return 0;
}
+
+static int fdt_path_del_node(void *fdt, const char *path)
+{
+ int nodeoffset;
+
+ nodeoffset = fdt_path_offset(fdt, path);
+ if (nodeoffset < 0)
+ return nodeoffset;
+
+ return fdt_del_node(fdt, nodeoffset);
+}
+
+static int fdt_path_set_name(void *fdt, const char *path, const char *name)
+{
+ int nodeoffset;
+
+ nodeoffset = fdt_path_offset(fdt, path);
+ if (nodeoffset < 0)
+ return nodeoffset;
+
+ return fdt_set_name(fdt, nodeoffset, name);
+}
+
+/*
+ * RK3582 is a variant of the RK3588S with some IP blocks disabled. What blocks
+ * are disabled/non-working is indicated by ip-state in OTP. ft_system_setup()
+ * is used to mark any cpu, gpu and/or vdec/venc node with status=fail as
+ * indicated by ip-state. Apply same policy as vendor U-Boot for RK3582, i.e.
+ * two big cpu cores, the gpu and one vdec/venc core is always failed. Enable
+ * OF_SYSTEM_SETUP to use the required DT fixups for RK3582 board variants.
+ */
+int ft_system_setup(void *blob, struct bd_info *bd)
+{
+ static const char * const cpu_node_names[] = {
+ "cpu@0", "cpu@100", "cpu@200", "cpu@300",
+ "cpu@400", "cpu@500", "cpu@600", "cpu@700",
+ };
+ int parent, node, i, comp_len, len, ret;
+ bool cluster1_removed = false;
+ u8 cpu_code[2], ip_state[3];
+ struct udevice *dev;
+ char soc_comp[16];
+ const char *comp;
+ void *data;
+
+ if (!IS_ENABLED(CONFIG_OF_SYSTEM_SETUP))
+ return 0;
+
+ if (!IS_ENABLED(CONFIG_ROCKCHIP_OTP) || !CONFIG_IS_ENABLED(MISC))
+ return -ENOSYS;
+
+ ret = uclass_get_device_by_driver(UCLASS_MISC,
+ DM_DRIVER_GET(rockchip_otp), &dev);
+ if (ret) {
+ log_debug("Could not find otp device, ret=%d\n", ret);
+ return ret;
+ }
+
+ /* cpu-code: SoC model, e.g. 0x35 0x82 or 0x35 0x88 */
+ ret = misc_read(dev, RK3588_OTP_CPU_CODE_OFFSET, cpu_code, 2);
+ if (ret < 0) {
+ log_debug("Could not read cpu-code, ret=%d\n", ret);
+ return ret;
+ }
+
+ log_debug("cpu-code: %02x %02x\n", cpu_code[0], cpu_code[1]);
+
+ /* only fail cores on rk3582 */
+ if (!(cpu_code[0] == 0x35 && cpu_code[1] == 0x82))
+ return 0;
+
+ ret = misc_read(dev, RK3588_OTP_IP_STATE_OFFSET, &ip_state, 3);
+ if (ret < 0) {
+ log_err("Could not read ip-state, ret=%d\n", ret);
+ return ret;
+ }
+
+ log_debug("ip-state: %02x %02x %02x (otp)\n",
+ ip_state[0], ip_state[1], ip_state[2]);
+
+ /* policy: fail entire big core cluster when one or more core is bad */
+ if (ip_state[0] & FAIL_CPU_CLUSTER1)
+ ip_state[0] |= FAIL_CPU_CLUSTER1;
+ if (ip_state[0] & FAIL_CPU_CLUSTER2)
+ ip_state[0] |= FAIL_CPU_CLUSTER2;
+
+ /* policy: always fail one big core cluster on rk3582 */
+ if (!(ip_state[0] & (FAIL_CPU_CLUSTER1 | FAIL_CPU_CLUSTER2)))
+ ip_state[0] |= FAIL_CPU_CLUSTER2;
+
+ /* policy: always fail gpu on rk3582 */
+ ip_state[1] |= FAIL_GPU;
+
+ /* policy: always fail one rkvdec core on rk3582 */
+ if (!(ip_state[1] & (FAIL_RKVDEC0 | FAIL_RKVDEC1)))
+ ip_state[1] |= FAIL_RKVDEC1;
+
+ /* policy: always fail one rkvenc core on rk3582 */
+ if (!(ip_state[2] & (FAIL_RKVENC0 | FAIL_RKVENC1)))
+ ip_state[2] |= FAIL_RKVENC1;
+
+ log_debug("ip-state: %02x %02x %02x (policy)\n",
+ ip_state[0], ip_state[1], ip_state[2]);
+
+ /* cpu cluster1: ip_state[0]: bit4~5 */
+ if ((ip_state[0] & FAIL_CPU_CLUSTER1) == FAIL_CPU_CLUSTER1) {
+ log_debug("remove cpu-map cluster1\n");
+ fdt_path_del_node(blob, "/cpus/cpu-map/cluster1");
+ cluster1_removed = true;
+ }
+
+ /* cpu cluster2: ip_state[0]: bit6~7 */
+ if ((ip_state[0] & FAIL_CPU_CLUSTER2) == FAIL_CPU_CLUSTER2) {
+ log_debug("remove cpu-map cluster2\n");
+ fdt_path_del_node(blob, "/cpus/cpu-map/cluster2");
+ } else if (cluster1_removed) {
+ /* cluster nodes must be named in a continuous series */
+ log_debug("rename cpu-map cluster2\n");
+ fdt_path_set_name(blob, "/cpus/cpu-map/cluster2", "cluster1");
+ }
+
+ /* gpu: ip_state[1]: bit1~4 */
+ if (ip_state[1] & FAIL_GPU) {
+ log_debug("fail gpu\n");
+ fdt_status_fail_by_pathf(blob, "/gpu@fb000000");
+ }
+
+ /* rkvdec: ip_state[1]: bit6,7 */
+ if (ip_state[1] & FAIL_RKVDEC0) {
+ log_debug("fail rkvdec0\n");
+ fdt_status_fail_by_pathf(blob, "/video-codec@fdc38000");
+ fdt_status_fail_by_pathf(blob, "/iommu@fdc38700");
+ }
+ if (ip_state[1] & FAIL_RKVDEC1) {
+ log_debug("fail rkvdec1\n");
+ fdt_status_fail_by_pathf(blob, "/video-codec@fdc40000");
+ fdt_status_fail_by_pathf(blob, "/iommu@fdc40700");
+ }
+
+ /* rkvenc: ip_state[2]: bit0,2 */
+ if (ip_state[2] & FAIL_RKVENC0) {
+ log_debug("fail rkvenc0\n");
+ fdt_status_fail_by_pathf(blob, "/video-codec@fdbd0000");
+ fdt_status_fail_by_pathf(blob, "/iommu@fdbdf000");
+ }
+ if (ip_state[2] & FAIL_RKVENC1) {
+ log_debug("fail rkvenc1\n");
+ fdt_status_fail_by_pathf(blob, "/video-codec@fdbe0000");
+ fdt_status_fail_by_pathf(blob, "/iommu@fdbef000");
+ }
+
+ parent = fdt_path_offset(blob, "/cpus");
+ if (parent < 0) {
+ log_err("Could not find /cpus, parent=%d\n", parent);
+ return parent;
+ }
+
+ /* cpu: ip_state[0]: bit0~7 */
+ for (i = 0; i < 8; i++) {
+ /* fail any bad cpu core */
+ if (!(ip_state[0] & BIT(i)))
+ continue;
+
+ node = fdt_subnode_offset(blob, parent, cpu_node_names[i]);
+ if (node >= 0) {
+ log_debug("fail cpu %s\n", cpu_node_names[i]);
+ fdt_status_fail(blob, node);
+ } else {
+ log_err("Could not find %s, node=%d\n",
+ cpu_node_names[i], node);
+ return node;
+ }
+ }
+
+ node = fdt_path_offset(blob, "/");
+ if (node < 0) {
+ log_err("Could not find /, node=%d\n", node);
+ return node;
+ }
+
+ snprintf(soc_comp, sizeof(soc_comp), "rockchip,rk35%x", cpu_code[1]);
+
+ for (i = 0, comp_len = 0;
+ (comp = fdt_stringlist_get(blob, node, "compatible", i, &len));
+ i++) {
+ /* stop at soc compatible */
+ if (!strcmp(comp, soc_comp) ||
+ !strcmp(comp, "rockchip,rk3588s") ||
+ !strcmp(comp, "rockchip,rk3588"))
+ break;
+
+ log_debug("compatible[%d]: %s\n", i, comp);
+ comp_len += len + 1;
+ }
+
+ /* truncate to only include board compatible */
+ fdt_setprop_placeholder(blob, node, "compatible", comp_len, &data);
+
+ /* append soc compatible */
+ fdt_appendprop_string(blob, node, "compatible", soc_comp);
+ fdt_appendprop_string(blob, node, "compatible", "rockchip,rk3588s");
+
+ return 0;
+}
--
Armbian

Loading