[PATCH v4 1/3] rockchip: Add initial RK3582 support

Kever Yang kever.yang at rock-chips.com
Mon Mar 9 15:45:47 CET 2026


On 2026/1/8 07:07, Jonas Karlman wrote:
> 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 <jonas at kwiboo.se>
Reviewed-by: Kever Yang <kever.yang at rock-chips.com>

Thanks,
- Kever
> ---
> Changes in v4:
> - Update policy to always fail gpu for RK3582
> - Drop code and comment related to RK3583
> - Update rkvdec node name to match latest mainline Linux DT patches
>
> Changes in v3:
> - Apply same policy for RK3582/RK3583 to match vendor U-Boot
>    linux-6.1-stan-rkr6 tag, allow use of the GPU and one vdec core.
> - Update rkvdec node name to match latest mainline Linux DT patches.
>
> Changes in v2:
> - Refactor code to first apply policy to ip-state and then fail cores
>    based on the updated ip-state
> - Add support for failing rkvdec and rkvenc cores
> - Append soc compatible to board model
> - Not picking up t-b tag due to significant changes to patch
> ---
>   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 6324c6f12867..c1138ffcb87f 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>
> @@ -240,6 +241,16 @@ int rockchip_dram_init_banksize_fixup(struct bd_info *bd)
>   
>   #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)
>   {
> @@ -285,3 +296,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 at 0", "cpu at 100", "cpu at 200", "cpu at 300",
> +		"cpu at 400", "cpu at 500", "cpu at 600", "cpu at 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 at 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 at fdc38000");
> +		fdt_status_fail_by_pathf(blob, "/iommu at fdc38700");
> +	}
> +	if (ip_state[1] & FAIL_RKVDEC1) {
> +		log_debug("fail rkvdec1\n");
> +		fdt_status_fail_by_pathf(blob, "/video-codec at fdc40000");
> +		fdt_status_fail_by_pathf(blob, "/iommu at 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 at fdbd0000");
> +		fdt_status_fail_by_pathf(blob, "/iommu at fdbdf000");
> +	}
> +	if (ip_state[2] & FAIL_RKVENC1) {
> +		log_debug("fail rkvenc1\n");
> +		fdt_status_fail_by_pathf(blob, "/video-codec at fdbe0000");
> +		fdt_status_fail_by_pathf(blob, "/iommu at 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;
> +}


More information about the U-Boot mailing list