* [PATCH 00/10] rockchip: Add initial support for RK3506
@ 2026-01-09 0:49 Jonas Karlman
2026-01-09 0:49 ` [PATCH 01/10] rockchip: mkimage: Add " Jonas Karlman
` (10 more replies)
0 siblings, 11 replies; 14+ messages in thread
From: Jonas Karlman @ 2026-01-09 0:49 UTC (permalink / raw)
To: Kever Yang, Simon Glass, Philipp Tomsich, Tom Rini
Cc: Aaron Griffith, u-boot, Jonas Karlman
This series add initial support for the Rockchip RK3506 SoC.
Clk and pinctrl drivers have been imported from vendor U-Boot with
some adjustments and fixes.
Upstream DT is currently not existing for RK3506, so this series does
not add support for any new boards, it only add initial arch support.
Please see my U-Boot rk3506 branch at [1] for a few more commits that
add DTs and defconfig for e.g. Luckfox Lyra variants and ArmSoM Forge1.
With this series, board DTs and defconfigs it should be possible to boot
into U-Boot proper (without OP-TEE) and still have support for MMC,
Ethernet, OTP, RNG, LEDs, buttons and USB gadget/host.
[1] https://source.denx.de/u-boot/contributors/kwiboo/u-boot/-/commits/rk3506
Finley Xiao (2):
dt-bindings: clock: rockchip: Add RK3506 clock and reset unit
clk: rockchip: Add support for RK3506
Jonas Karlman (6):
ram: rockchip: Add basic support for RK3506
pinctrl: rockchip: Use syscon_regmap_lookup_by_phandle()
rockchip: otp: Add support for RK3506
phy: rockchip-inno-usb2: Add support for RK3506
net: dwc_eth_qos_rockchip: Add support for RK3506
arch: arm: rockchip: Add initial support for RK3506
Xuhui Lin (1):
rockchip: mkimage: Add support for RK3506
Ye Zhang (1):
pinctrl: rockchip: Add support for RK3506
arch/arm/include/asm/arch-rk3506/boot0.h | 9 +
arch/arm/include/asm/arch-rk3506/gpio.h | 9 +
arch/arm/include/asm/arch-rockchip/clock.h | 10 +
.../include/asm/arch-rockchip/cru_rk3506.h | 220 +++
arch/arm/mach-rockchip/Kconfig | 43 +
arch/arm/mach-rockchip/Makefile | 1 +
arch/arm/mach-rockchip/rk3506/Kconfig | 15 +
arch/arm/mach-rockchip/rk3506/Makefile | 5 +
arch/arm/mach-rockchip/rk3506/clk_rk3506.c | 16 +
arch/arm/mach-rockchip/rk3506/rk3506.c | 130 ++
arch/arm/mach-rockchip/rk3506/syscon_rk3506.c | 19 +
drivers/clk/rockchip/Makefile | 1 +
drivers/clk/rockchip/clk_rk3506.c | 1212 +++++++++++++++++
drivers/misc/rockchip-otp.c | 4 +
drivers/net/dwc_eth_qos.c | 4 +
drivers/net/dwc_eth_qos_rockchip.c | 86 ++
drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 20 +
drivers/pinctrl/rockchip/Makefile | 1 +
drivers/pinctrl/rockchip/pinctrl-rk3506.c | 462 +++++++
.../pinctrl/rockchip/pinctrl-rockchip-core.c | 46 +-
drivers/pinctrl/rockchip/pinctrl-rockchip.h | 1 +
drivers/ram/rockchip/Makefile | 1 +
drivers/ram/rockchip/sdram_rk3506.c | 33 +
drivers/reset/Makefile | 2 +-
drivers/reset/rst-rk3506.c | 222 +++
drivers/usb/gadget/Kconfig | 1 +
.../Bindings/clock/rockchip,rk3506-cru.yaml | 55 +
.../dt-bindings/clock/rockchip,rk3506-cru.h | 285 ++++
.../dt-bindings/reset/rockchip,rk3506-cru.h | 211 +++
include/configs/rk3506_common.h | 38 +
tools/rkcommon.c | 1 +
31 files changed, 3136 insertions(+), 27 deletions(-)
create mode 100644 arch/arm/include/asm/arch-rk3506/boot0.h
create mode 100644 arch/arm/include/asm/arch-rk3506/gpio.h
create mode 100644 arch/arm/include/asm/arch-rockchip/cru_rk3506.h
create mode 100644 arch/arm/mach-rockchip/rk3506/Kconfig
create mode 100644 arch/arm/mach-rockchip/rk3506/Makefile
create mode 100644 arch/arm/mach-rockchip/rk3506/clk_rk3506.c
create mode 100644 arch/arm/mach-rockchip/rk3506/rk3506.c
create mode 100644 arch/arm/mach-rockchip/rk3506/syscon_rk3506.c
create mode 100644 drivers/clk/rockchip/clk_rk3506.c
create mode 100644 drivers/pinctrl/rockchip/pinctrl-rk3506.c
create mode 100644 drivers/ram/rockchip/sdram_rk3506.c
create mode 100644 drivers/reset/rst-rk3506.c
create mode 100644 dts/upstream/Bindings/clock/rockchip,rk3506-cru.yaml
create mode 100644 dts/upstream/include/dt-bindings/clock/rockchip,rk3506-cru.h
create mode 100644 dts/upstream/include/dt-bindings/reset/rockchip,rk3506-cru.h
create mode 100644 include/configs/rk3506_common.h
--
2.52.0
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 01/10] rockchip: mkimage: Add support for RK3506
2026-01-09 0:49 [PATCH 00/10] rockchip: Add initial support for RK3506 Jonas Karlman
@ 2026-01-09 0:49 ` Jonas Karlman
2026-01-09 0:49 ` [PATCH 02/10] ram: rockchip: Add basic " Jonas Karlman
` (9 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Jonas Karlman @ 2026-01-09 0:49 UTC (permalink / raw)
To: Kever Yang, Simon Glass, Philipp Tomsich, Tom Rini
Cc: Aaron Griffith, u-boot, Jonas Karlman, Xuhui Lin
From: Xuhui Lin <xuhui.lin@rock-chips.com>
Add support for generating Rockchip Boot Image for RK3506.
The RK3506 has 48 KiB SRAM and 4 KiB is reserved for BootROM.
Signed-off-by: Xuhui Lin <xuhui.lin@rock-chips.com>
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
tools/rkcommon.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/tools/rkcommon.c b/tools/rkcommon.c
index e7e78ef7e5b7..784e542ea27c 100644
--- a/tools/rkcommon.c
+++ b/tools/rkcommon.c
@@ -150,6 +150,7 @@ static struct spl_info spl_infos[] = {
{ "rk3399", "RK33", 0x30000 - 0x2000, false, RK_HEADER_V1 },
{ "rv1108", "RK11", 0x1800, false, RK_HEADER_V1 },
{ "rv1126", "110B", 0x10000 - 0x1000, false, RK_HEADER_V1 },
+ { "rk3506", "RK35", 0xC000 - 0x1000, false, RK_HEADER_V2 },
{ "rk3528", "RK35", 0x10000 - 0x1000, false, RK_HEADER_V2 },
{ "rk3568", "RK35", 0x10000 - 0x1000, false, RK_HEADER_V2 },
{ "rk3576", "RK35", 0x80000 - 0x1000, false, RK_HEADER_V2 },
--
2.52.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 02/10] ram: rockchip: Add basic support for RK3506
2026-01-09 0:49 [PATCH 00/10] rockchip: Add initial support for RK3506 Jonas Karlman
2026-01-09 0:49 ` [PATCH 01/10] rockchip: mkimage: Add " Jonas Karlman
@ 2026-01-09 0:49 ` Jonas Karlman
2026-01-09 0:49 ` [PATCH 03/10] dt-bindings: clock: rockchip: Add RK3506 clock and reset unit Jonas Karlman
` (8 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Jonas Karlman @ 2026-01-09 0:49 UTC (permalink / raw)
To: Kever Yang, Simon Glass, Philipp Tomsich, Tom Rini
Cc: Aaron Griffith, u-boot, Jonas Karlman
Add support for reading DRAM size information from PMUGRF os_reg2 reg.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/ram/rockchip/Makefile | 1 +
drivers/ram/rockchip/sdram_rk3506.c | 33 +++++++++++++++++++++++++++++
2 files changed, 34 insertions(+)
create mode 100644 drivers/ram/rockchip/sdram_rk3506.c
diff --git a/drivers/ram/rockchip/Makefile b/drivers/ram/rockchip/Makefile
index fd94aad0cd49..27921ae4921a 100644
--- a/drivers/ram/rockchip/Makefile
+++ b/drivers/ram/rockchip/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_ROCKCHIP_RK3288) = sdram_rk3288.o
obj-$(CONFIG_ROCKCHIP_RK3308) = sdram_rk3308.o
obj-$(CONFIG_ROCKCHIP_RK3328) = sdram_rk3328.o sdram_pctl_px30.o sdram_phy_px30.o
obj-$(CONFIG_ROCKCHIP_RK3399) += sdram_rk3399.o
+obj-$(CONFIG_ROCKCHIP_RK3506) += sdram_rk3506.o
obj-$(CONFIG_ROCKCHIP_RK3528) += sdram_rk3528.o
obj-$(CONFIG_ROCKCHIP_RK3568) += sdram_rk3568.o
obj-$(CONFIG_ROCKCHIP_RK3576) += sdram_rk3576.o
diff --git a/drivers/ram/rockchip/sdram_rk3506.c b/drivers/ram/rockchip/sdram_rk3506.c
new file mode 100644
index 000000000000..a8396ea88883
--- /dev/null
+++ b/drivers/ram/rockchip/sdram_rk3506.c
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright Contributors to the U-Boot project.
+
+#include <dm.h>
+#include <ram.h>
+#include <asm/arch-rockchip/sdram.h>
+
+#define PMUGRF_BASE 0xff910000
+#define OS_REG2_REG 0x208
+
+static int rk3506_dmc_get_info(struct udevice *dev, struct ram_info *info)
+{
+ info->base = CFG_SYS_SDRAM_BASE;
+ info->size = rockchip_sdram_size(PMUGRF_BASE + OS_REG2_REG);
+
+ return 0;
+}
+
+static struct ram_ops rk3506_dmc_ops = {
+ .get_info = rk3506_dmc_get_info,
+};
+
+static const struct udevice_id rk3506_dmc_ids[] = {
+ { .compatible = "rockchip,rk3506-dmc" },
+ { }
+};
+
+U_BOOT_DRIVER(rockchip_rk3506_dmc) = {
+ .name = "rockchip_rk3506_dmc",
+ .id = UCLASS_RAM,
+ .of_match = rk3506_dmc_ids,
+ .ops = &rk3506_dmc_ops,
+};
--
2.52.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 03/10] dt-bindings: clock: rockchip: Add RK3506 clock and reset unit
2026-01-09 0:49 [PATCH 00/10] rockchip: Add initial support for RK3506 Jonas Karlman
2026-01-09 0:49 ` [PATCH 01/10] rockchip: mkimage: Add " Jonas Karlman
2026-01-09 0:49 ` [PATCH 02/10] ram: rockchip: Add basic " Jonas Karlman
@ 2026-01-09 0:49 ` Jonas Karlman
2026-01-09 0:49 ` [PATCH 04/10] clk: rockchip: Add support for RK3506 Jonas Karlman
` (7 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Jonas Karlman @ 2026-01-09 0:49 UTC (permalink / raw)
To: Kever Yang, Simon Glass, Philipp Tomsich, Tom Rini, Sumit Garg,
Finley Xiao, Heiko Stuebner
Cc: Aaron Griffith, u-boot, Jonas Karlman, Elaine Zhang, Conor Dooley
From: Finley Xiao <finley.xiao@rock-chips.com>
Add device tree bindings for clock and reset unit on RK3506 SoC.
Add clock and reset IDs for RK3506 SoC.
Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
Link: https://patch.msgid.link/20251121075350.2564860-2-zhangqing@rock-chips.com
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
[ upstream commit: 84898f8e9cea06f8178fc5ca53f068180f7bfba0 ]
(cherry picked from commit 516951213a82094f7f49f149cbf3c66dfb14c65d)
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
.../Bindings/clock/rockchip,rk3506-cru.yaml | 55 ++++
.../dt-bindings/clock/rockchip,rk3506-cru.h | 285 ++++++++++++++++++
.../dt-bindings/reset/rockchip,rk3506-cru.h | 211 +++++++++++++
3 files changed, 551 insertions(+)
create mode 100644 dts/upstream/Bindings/clock/rockchip,rk3506-cru.yaml
create mode 100644 dts/upstream/include/dt-bindings/clock/rockchip,rk3506-cru.h
create mode 100644 dts/upstream/include/dt-bindings/reset/rockchip,rk3506-cru.h
diff --git a/dts/upstream/Bindings/clock/rockchip,rk3506-cru.yaml b/dts/upstream/Bindings/clock/rockchip,rk3506-cru.yaml
new file mode 100644
index 000000000000..ca940475336c
--- /dev/null
+++ b/dts/upstream/Bindings/clock/rockchip,rk3506-cru.yaml
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/rockchip,rk3506-cru.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip RK3506 Clock and Reset Unit (CRU)
+
+maintainers:
+ - Finley Xiao <finley.xiao@rock-chips.com>
+ - Heiko Stuebner <heiko@sntech.de>
+
+description:
+ The RK3506 CRU generates the clock and also implements reset for SoC
+ peripherals.
+
+properties:
+ compatible:
+ const: rockchip,rk3506-cru
+
+ reg:
+ maxItems: 1
+
+ "#clock-cells":
+ const: 1
+
+ "#reset-cells":
+ const: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ const: xin
+
+required:
+ - compatible
+ - reg
+ - "#clock-cells"
+ - "#reset-cells"
+ - clocks
+ - clock-names
+
+additionalProperties: false
+
+examples:
+ - |
+ clock-controller@ff9a0000 {
+ compatible = "rockchip,rk3506-cru";
+ reg = <0xff9a0000 0x20000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ clocks = <&xin24m>;
+ clock-names = "xin";
+ };
diff --git a/dts/upstream/include/dt-bindings/clock/rockchip,rk3506-cru.h b/dts/upstream/include/dt-bindings/clock/rockchip,rk3506-cru.h
new file mode 100644
index 000000000000..71d7dda23cc9
--- /dev/null
+++ b/dts/upstream/include/dt-bindings/clock/rockchip,rk3506-cru.h
@@ -0,0 +1,285 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) 2023-2025 Rockchip Electronics Co., Ltd.
+ * Author: Finley Xiao <finley.xiao@rock-chips.com>
+ */
+
+#ifndef _DT_BINDINGS_CLK_ROCKCHIP_RK3506_H
+#define _DT_BINDINGS_CLK_ROCKCHIP_RK3506_H
+
+/* cru plls */
+#define PLL_GPLL 0
+#define PLL_V0PLL 1
+#define PLL_V1PLL 2
+
+/* cru-clocks indices */
+#define ARMCLK 3
+#define CLK_DDR 4
+#define XIN24M_GATE 5
+#define CLK_GPLL_GATE 6
+#define CLK_V0PLL_GATE 7
+#define CLK_V1PLL_GATE 8
+#define CLK_GPLL_DIV 9
+#define CLK_GPLL_DIV_100M 10
+#define CLK_V0PLL_DIV 11
+#define CLK_V1PLL_DIV 12
+#define CLK_INT_VOICE_MATRIX0 13
+#define CLK_INT_VOICE_MATRIX1 14
+#define CLK_INT_VOICE_MATRIX2 15
+#define CLK_FRAC_UART_MATRIX0_MUX 16
+#define CLK_FRAC_UART_MATRIX1_MUX 17
+#define CLK_FRAC_VOICE_MATRIX0_MUX 18
+#define CLK_FRAC_VOICE_MATRIX1_MUX 19
+#define CLK_FRAC_COMMON_MATRIX0_MUX 20
+#define CLK_FRAC_COMMON_MATRIX1_MUX 21
+#define CLK_FRAC_COMMON_MATRIX2_MUX 22
+#define CLK_FRAC_UART_MATRIX0 23
+#define CLK_FRAC_UART_MATRIX1 24
+#define CLK_FRAC_VOICE_MATRIX0 25
+#define CLK_FRAC_VOICE_MATRIX1 26
+#define CLK_FRAC_COMMON_MATRIX0 27
+#define CLK_FRAC_COMMON_MATRIX1 28
+#define CLK_FRAC_COMMON_MATRIX2 29
+#define CLK_REF_USBPHY_TOP 30
+#define CLK_REF_DPHY_TOP 31
+#define ACLK_CORE_ROOT 32
+#define PCLK_CORE_ROOT 33
+#define PCLK_DBG 34
+#define PCLK_CORE_GRF 35
+#define PCLK_CORE_CRU 36
+#define CLK_CORE_EMA_DETECT 37
+#define CLK_REF_PVTPLL_CORE 38
+#define PCLK_GPIO1 39
+#define DBCLK_GPIO1 40
+#define ACLK_CORE_PERI_ROOT 41
+#define HCLK_CORE_PERI_ROOT 42
+#define PCLK_CORE_PERI_ROOT 43
+#define CLK_DSMC 44
+#define ACLK_DSMC 45
+#define PCLK_DSMC 46
+#define CLK_FLEXBUS_TX 47
+#define CLK_FLEXBUS_RX 48
+#define ACLK_FLEXBUS 49
+#define HCLK_FLEXBUS 50
+#define ACLK_DSMC_SLV 51
+#define HCLK_DSMC_SLV 52
+#define ACLK_BUS_ROOT 53
+#define HCLK_BUS_ROOT 54
+#define PCLK_BUS_ROOT 55
+#define ACLK_SYSRAM 56
+#define HCLK_SYSRAM 57
+#define ACLK_DMAC0 58
+#define ACLK_DMAC1 59
+#define HCLK_M0 60
+#define PCLK_BUS_GRF 61
+#define PCLK_TIMER 62
+#define CLK_TIMER0_CH0 63
+#define CLK_TIMER0_CH1 64
+#define CLK_TIMER0_CH2 65
+#define CLK_TIMER0_CH3 66
+#define CLK_TIMER0_CH4 67
+#define CLK_TIMER0_CH5 68
+#define PCLK_WDT0 69
+#define TCLK_WDT0 70
+#define PCLK_WDT1 71
+#define TCLK_WDT1 72
+#define PCLK_MAILBOX 73
+#define PCLK_INTMUX 74
+#define PCLK_SPINLOCK 75
+#define PCLK_DDRC 76
+#define HCLK_DDRPHY 77
+#define PCLK_DDRMON 78
+#define CLK_DDRMON_OSC 79
+#define PCLK_STDBY 80
+#define HCLK_USBOTG0 81
+#define HCLK_USBOTG0_PMU 82
+#define CLK_USBOTG0_ADP 83
+#define HCLK_USBOTG1 84
+#define HCLK_USBOTG1_PMU 85
+#define CLK_USBOTG1_ADP 86
+#define PCLK_USBPHY 87
+#define ACLK_DMA2DDR 88
+#define PCLK_DMA2DDR 89
+#define STCLK_M0 90
+#define CLK_DDRPHY 91
+#define CLK_DDRC_SRC 92
+#define ACLK_DDRC_0 93
+#define ACLK_DDRC_1 94
+#define CLK_DDRC 95
+#define CLK_DDRMON 96
+#define HCLK_LSPERI_ROOT 97
+#define PCLK_LSPERI_ROOT 98
+#define PCLK_UART0 99
+#define PCLK_UART1 100
+#define PCLK_UART2 101
+#define PCLK_UART3 102
+#define PCLK_UART4 103
+#define SCLK_UART0 104
+#define SCLK_UART1 105
+#define SCLK_UART2 106
+#define SCLK_UART3 107
+#define SCLK_UART4 108
+#define PCLK_I2C0 109
+#define CLK_I2C0 110
+#define PCLK_I2C1 111
+#define CLK_I2C1 112
+#define PCLK_I2C2 113
+#define CLK_I2C2 114
+#define PCLK_PWM1 115
+#define CLK_PWM1 116
+#define CLK_OSC_PWM1 117
+#define CLK_RC_PWM1 118
+#define CLK_FREQ_PWM1 119
+#define CLK_COUNTER_PWM1 120
+#define PCLK_SPI0 121
+#define CLK_SPI0 122
+#define PCLK_SPI1 123
+#define CLK_SPI1 124
+#define PCLK_GPIO2 125
+#define DBCLK_GPIO2 126
+#define PCLK_GPIO3 127
+#define DBCLK_GPIO3 128
+#define PCLK_GPIO4 129
+#define DBCLK_GPIO4 130
+#define HCLK_CAN0 131
+#define CLK_CAN0 132
+#define HCLK_CAN1 133
+#define CLK_CAN1 134
+#define HCLK_PDM 135
+#define MCLK_PDM 136
+#define CLKOUT_PDM 137
+#define MCLK_SPDIFTX 138
+#define HCLK_SPDIFTX 139
+#define HCLK_SPDIFRX 140
+#define MCLK_SPDIFRX 141
+#define MCLK_SAI0 142
+#define HCLK_SAI0 143
+#define MCLK_OUT_SAI0 144
+#define MCLK_SAI1 145
+#define HCLK_SAI1 146
+#define MCLK_OUT_SAI1 147
+#define HCLK_ASRC0 148
+#define CLK_ASRC0 149
+#define HCLK_ASRC1 150
+#define CLK_ASRC1 151
+#define PCLK_CRU 152
+#define PCLK_PMU_ROOT 153
+#define MCLK_ASRC0 154
+#define MCLK_ASRC1 155
+#define MCLK_ASRC2 156
+#define MCLK_ASRC3 157
+#define LRCK_ASRC0_SRC 158
+#define LRCK_ASRC0_DST 159
+#define LRCK_ASRC1_SRC 160
+#define LRCK_ASRC1_DST 161
+#define ACLK_HSPERI_ROOT 162
+#define HCLK_HSPERI_ROOT 163
+#define PCLK_HSPERI_ROOT 164
+#define CCLK_SRC_SDMMC 165
+#define HCLK_SDMMC 166
+#define HCLK_FSPI 167
+#define SCLK_FSPI 168
+#define PCLK_SPI2 169
+#define ACLK_MAC0 170
+#define ACLK_MAC1 171
+#define PCLK_MAC0 172
+#define PCLK_MAC1 173
+#define CLK_MAC_ROOT 174
+#define CLK_MAC0 175
+#define CLK_MAC1 176
+#define MCLK_SAI2 177
+#define HCLK_SAI2 178
+#define MCLK_OUT_SAI2 179
+#define MCLK_SAI3_SRC 180
+#define HCLK_SAI3 181
+#define MCLK_SAI3 182
+#define MCLK_OUT_SAI3 183
+#define MCLK_SAI4_SRC 184
+#define HCLK_SAI4 185
+#define MCLK_SAI4 186
+#define HCLK_DSM 187
+#define MCLK_DSM 188
+#define PCLK_AUDIO_ADC 189
+#define MCLK_AUDIO_ADC 190
+#define MCLK_AUDIO_ADC_DIV4 191
+#define PCLK_SARADC 192
+#define CLK_SARADC 193
+#define PCLK_OTPC_NS 194
+#define CLK_SBPI_OTPC_NS 195
+#define CLK_USER_OTPC_NS 196
+#define PCLK_UART5 197
+#define SCLK_UART5 198
+#define PCLK_GPIO234_IOC 199
+#define CLK_MAC_PTP_ROOT 200
+#define CLK_MAC0_PTP 201
+#define CLK_MAC1_PTP 202
+#define CLK_SPI2 203
+#define ACLK_VIO_ROOT 204
+#define HCLK_VIO_ROOT 205
+#define PCLK_VIO_ROOT 206
+#define HCLK_RGA 207
+#define ACLK_RGA 208
+#define CLK_CORE_RGA 209
+#define ACLK_VOP 210
+#define HCLK_VOP 211
+#define DCLK_VOP 212
+#define PCLK_DPHY 213
+#define PCLK_DSI_HOST 214
+#define PCLK_TSADC 215
+#define CLK_TSADC 216
+#define CLK_TSADC_TSEN 217
+#define PCLK_GPIO1_IOC 218
+#define PCLK_OTPC_S 219
+#define CLK_SBPI_OTPC_S 220
+#define CLK_USER_OTPC_S 221
+#define PCLK_OTP_MASK 222
+#define PCLK_KEYREADER 223
+#define HCLK_BOOTROM 224
+#define PCLK_DDR_SERVICE 225
+#define HCLK_CRYPTO_S 226
+#define HCLK_KEYLAD 227
+#define CLK_CORE_CRYPTO 228
+#define CLK_PKA_CRYPTO 229
+#define CLK_CORE_CRYPTO_S 230
+#define CLK_PKA_CRYPTO_S 231
+#define ACLK_CRYPTO_S 232
+#define HCLK_RNG_S 233
+#define CLK_CORE_CRYPTO_NS 234
+#define CLK_PKA_CRYPTO_NS 235
+#define ACLK_CRYPTO_NS 236
+#define HCLK_CRYPTO_NS 237
+#define HCLK_RNG 238
+#define CLK_PMU 239
+#define PCLK_PMU 240
+#define CLK_PMU_32K 241
+#define PCLK_PMU_CRU 242
+#define PCLK_PMU_GRF 243
+#define PCLK_GPIO0_IOC 244
+#define PCLK_GPIO0 245
+#define DBCLK_GPIO0 246
+#define PCLK_GPIO1_SHADOW 247
+#define DBCLK_GPIO1_SHADOW 248
+#define PCLK_PMU_HP_TIMER 249
+#define CLK_PMU_HP_TIMER 250
+#define CLK_PMU_HP_TIMER_32K 251
+#define PCLK_PWM0 252
+#define CLK_PWM0 253
+#define CLK_OSC_PWM0 254
+#define CLK_RC_PWM0 255
+#define CLK_MAC_OUT 256
+#define CLK_REF_OUT0 257
+#define CLK_REF_OUT1 258
+#define CLK_32K_FRAC 259
+#define CLK_32K_RC 260
+#define CLK_32K 261
+#define CLK_32K_PMU 262
+#define PCLK_TOUCH_KEY 263
+#define CLK_TOUCH_KEY 264
+#define CLK_REF_PHY_PLL 265
+#define CLK_REF_PHY_PMU_MUX 266
+#define CLK_WIFI_OUT 267
+#define CLK_V0PLL_REF 268
+#define CLK_V1PLL_REF 269
+#define CLK_32K_FRAC_MUX 270
+
+#endif
diff --git a/dts/upstream/include/dt-bindings/reset/rockchip,rk3506-cru.h b/dts/upstream/include/dt-bindings/reset/rockchip,rk3506-cru.h
new file mode 100644
index 000000000000..31c0d4aa410f
--- /dev/null
+++ b/dts/upstream/include/dt-bindings/reset/rockchip,rk3506-cru.h
@@ -0,0 +1,211 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) 2023-2025 Rockchip Electronics Co., Ltd.
+ * Author: Finley Xiao <finley.xiao@rock-chips.com>
+ */
+
+#ifndef _DT_BINDINGS_REST_ROCKCHIP_RK3506_H
+#define _DT_BINDINGS_REST_ROCKCHIP_RK3506_H
+
+/* CRU-->SOFTRST_CON00 */
+#define SRST_NCOREPORESET0_AC 0
+#define SRST_NCOREPORESET1_AC 1
+#define SRST_NCOREPORESET2_AC 2
+#define SRST_NCORESET0_AC 3
+#define SRST_NCORESET1_AC 4
+#define SRST_NCORESET2_AC 5
+#define SRST_NL2RESET_AC 6
+#define SRST_A_CORE_BIU_AC 7
+#define SRST_H_M0_AC 8
+
+/* CRU-->SOFTRST_CON02 */
+#define SRST_NDBGRESET 9
+#define SRST_P_CORE_BIU 10
+#define SRST_PMU 11
+
+/* CRU-->SOFTRST_CON03 */
+#define SRST_P_DBG 12
+#define SRST_POT_DBG 13
+#define SRST_P_CORE_GRF 14
+#define SRST_CORE_EMA_DETECT 15
+#define SRST_REF_PVTPLL_CORE 16
+#define SRST_P_GPIO1 17
+#define SRST_DB_GPIO1 18
+
+/* CRU-->SOFTRST_CON04 */
+#define SRST_A_CORE_PERI_BIU 19
+#define SRST_A_DSMC 20
+#define SRST_P_DSMC 21
+#define SRST_FLEXBUS 22
+#define SRST_A_FLEXBUS 23
+#define SRST_H_FLEXBUS 24
+#define SRST_A_DSMC_SLV 25
+#define SRST_H_DSMC_SLV 26
+#define SRST_DSMC_SLV 27
+
+/* CRU-->SOFTRST_CON05 */
+#define SRST_A_BUS_BIU 28
+#define SRST_H_BUS_BIU 29
+#define SRST_P_BUS_BIU 30
+#define SRST_A_SYSRAM 31
+#define SRST_H_SYSRAM 32
+#define SRST_A_DMAC0 33
+#define SRST_A_DMAC1 34
+#define SRST_H_M0 35
+#define SRST_M0_JTAG 36
+#define SRST_H_CRYPTO 37
+
+/* CRU-->SOFTRST_CON06 */
+#define SRST_H_RNG 38
+#define SRST_P_BUS_GRF 39
+#define SRST_P_TIMER0 40
+#define SRST_TIMER0_CH0 41
+#define SRST_TIMER0_CH1 42
+#define SRST_TIMER0_CH2 43
+#define SRST_TIMER0_CH3 44
+#define SRST_TIMER0_CH4 45
+#define SRST_TIMER0_CH5 46
+#define SRST_P_WDT0 47
+#define SRST_T_WDT0 48
+#define SRST_P_WDT1 49
+#define SRST_T_WDT1 50
+#define SRST_P_MAILBOX 51
+#define SRST_P_INTMUX 52
+#define SRST_P_SPINLOCK 53
+
+/* CRU-->SOFTRST_CON07 */
+#define SRST_P_DDRC 54
+#define SRST_H_DDRPHY 55
+#define SRST_P_DDRMON 56
+#define SRST_DDRMON_OSC 57
+#define SRST_P_DDR_LPC 58
+#define SRST_H_USBOTG0 59
+#define SRST_USBOTG0_ADP 60
+#define SRST_H_USBOTG1 61
+#define SRST_USBOTG1_ADP 62
+#define SRST_P_USBPHY 63
+#define SRST_USBPHY_POR 64
+#define SRST_USBPHY_OTG0 65
+#define SRST_USBPHY_OTG1 66
+
+/* CRU-->SOFTRST_CON08 */
+#define SRST_A_DMA2DDR 67
+#define SRST_P_DMA2DDR 68
+
+/* CRU-->SOFTRST_CON09 */
+#define SRST_USBOTG0_UTMI 69
+#define SRST_USBOTG1_UTMI 70
+
+/* CRU-->SOFTRST_CON10 */
+#define SRST_A_DDRC_0 71
+#define SRST_A_DDRC_1 72
+#define SRST_A_DDR_BIU 73
+#define SRST_DDRC 74
+#define SRST_DDRMON 75
+
+/* CRU-->SOFTRST_CON11 */
+#define SRST_H_LSPERI_BIU 76
+#define SRST_P_UART0 77
+#define SRST_P_UART1 78
+#define SRST_P_UART2 79
+#define SRST_P_UART3 80
+#define SRST_P_UART4 81
+#define SRST_UART0 82
+#define SRST_UART1 83
+#define SRST_UART2 84
+#define SRST_UART3 85
+#define SRST_UART4 86
+#define SRST_P_I2C0 87
+#define SRST_I2C0 88
+
+/* CRU-->SOFTRST_CON12 */
+#define SRST_P_I2C1 89
+#define SRST_I2C1 90
+#define SRST_P_I2C2 91
+#define SRST_I2C2 92
+#define SRST_P_PWM1 93
+#define SRST_PWM1 94
+#define SRST_P_SPI0 95
+#define SRST_SPI0 96
+#define SRST_P_SPI1 97
+#define SRST_SPI1 98
+#define SRST_P_GPIO2 99
+#define SRST_DB_GPIO2 100
+
+/* CRU-->SOFTRST_CON13 */
+#define SRST_P_GPIO3 101
+#define SRST_DB_GPIO3 102
+#define SRST_P_GPIO4 103
+#define SRST_DB_GPIO4 104
+#define SRST_H_CAN0 105
+#define SRST_CAN0 106
+#define SRST_H_CAN1 107
+#define SRST_CAN1 108
+#define SRST_H_PDM 109
+#define SRST_M_PDM 110
+#define SRST_PDM 111
+#define SRST_SPDIFTX 112
+#define SRST_H_SPDIFTX 113
+#define SRST_H_SPDIFRX 114
+#define SRST_SPDIFRX 115
+#define SRST_M_SAI0 116
+
+/* CRU-->SOFTRST_CON14 */
+#define SRST_H_SAI0 117
+#define SRST_M_SAI1 118
+#define SRST_H_SAI1 119
+#define SRST_H_ASRC0 120
+#define SRST_ASRC0 121
+#define SRST_H_ASRC1 122
+#define SRST_ASRC1 123
+
+/* CRU-->SOFTRST_CON17 */
+#define SRST_H_HSPERI_BIU 124
+#define SRST_H_SDMMC 125
+#define SRST_H_FSPI 126
+#define SRST_S_FSPI 127
+#define SRST_P_SPI2 128
+#define SRST_A_MAC0 129
+#define SRST_A_MAC1 130
+
+/* CRU-->SOFTRST_CON18 */
+#define SRST_M_SAI2 131
+#define SRST_H_SAI2 132
+#define SRST_H_SAI3 133
+#define SRST_M_SAI3 134
+#define SRST_H_SAI4 135
+#define SRST_M_SAI4 136
+#define SRST_H_DSM 137
+#define SRST_M_DSM 138
+#define SRST_P_AUDIO_ADC 139
+#define SRST_M_AUDIO_ADC 140
+
+/* CRU-->SOFTRST_CON19 */
+#define SRST_P_SARADC 141
+#define SRST_SARADC 142
+#define SRST_SARADC_PHY 143
+#define SRST_P_OTPC_NS 144
+#define SRST_SBPI_OTPC_NS 145
+#define SRST_USER_OTPC_NS 146
+#define SRST_P_UART5 147
+#define SRST_UART5 148
+#define SRST_P_GPIO234_IOC 149
+
+/* CRU-->SOFTRST_CON21 */
+#define SRST_A_VIO_BIU 150
+#define SRST_H_VIO_BIU 151
+#define SRST_H_RGA 152
+#define SRST_A_RGA 153
+#define SRST_CORE_RGA 154
+#define SRST_A_VOP 155
+#define SRST_H_VOP 156
+#define SRST_VOP 157
+#define SRST_P_DPHY 158
+#define SRST_P_DSI_HOST 159
+#define SRST_P_TSADC 160
+#define SRST_TSADC 161
+
+/* CRU-->SOFTRST_CON22 */
+#define SRST_P_GPIO1_IOC 162
+
+#endif
--
2.52.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 04/10] clk: rockchip: Add support for RK3506
2026-01-09 0:49 [PATCH 00/10] rockchip: Add initial support for RK3506 Jonas Karlman
` (2 preceding siblings ...)
2026-01-09 0:49 ` [PATCH 03/10] dt-bindings: clock: rockchip: Add RK3506 clock and reset unit Jonas Karlman
@ 2026-01-09 0:49 ` Jonas Karlman
2026-01-09 0:49 ` [PATCH 05/10] pinctrl: rockchip: Use syscon_regmap_lookup_by_phandle() Jonas Karlman
` (6 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Jonas Karlman @ 2026-01-09 0:49 UTC (permalink / raw)
To: Kever Yang, Simon Glass, Philipp Tomsich, Tom Rini,
Lukasz Majewski
Cc: Aaron Griffith, u-boot, Jonas Karlman, Finley Xiao
From: Finley Xiao <finley.xiao@rock-chips.com>
Add clock driver for RK3506.
Imported from vendor U-Boot linux-6.1-stan-rkr6 tag with minor
adjustments and fixes for mainline.
Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
arch/arm/include/asm/arch-rockchip/clock.h | 10 +
.../include/asm/arch-rockchip/cru_rk3506.h | 220 +++
drivers/clk/rockchip/Makefile | 1 +
drivers/clk/rockchip/clk_rk3506.c | 1212 +++++++++++++++++
drivers/reset/Makefile | 2 +-
drivers/reset/rst-rk3506.c | 222 +++
6 files changed, 1666 insertions(+), 1 deletion(-)
create mode 100644 arch/arm/include/asm/arch-rockchip/cru_rk3506.h
create mode 100644 drivers/clk/rockchip/clk_rk3506.c
create mode 100644 drivers/reset/rst-rk3506.c
diff --git a/arch/arm/include/asm/arch-rockchip/clock.h b/arch/arm/include/asm/arch-rockchip/clock.h
index 3c204501f709..95b08bfd046f 100644
--- a/arch/arm/include/asm/arch-rockchip/clock.h
+++ b/arch/arm/include/asm/arch-rockchip/clock.h
@@ -214,6 +214,16 @@ int rockchip_reset_bind(struct udevice *pdev, u32 reg_offset, u32 reg_number);
*/
int rockchip_reset_bind_lut(struct udevice *pdev, const int *lookup_table,
u32 reg_offset, u32 reg_number);
+/*
+ * rk3506_reset_bind_lut() - Bind soft reset device as child of clock device
+ * using dedicated RK3506 lookup table
+ *
+ * @pdev: clock udevice
+ * @reg_offset: the first offset in cru for softreset registers
+ * @reg_number: the reg numbers of softreset registers
+ * Return: 0 success, or error value
+ */
+int rk3506_reset_bind_lut(struct udevice *pdev, u32 reg_offset, u32 reg_number);
/*
* rk3528_reset_bind_lut() - Bind soft reset device as child of clock device
* using dedicated RK3528 lookup table
diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk3506.h b/arch/arm/include/asm/arch-rockchip/cru_rk3506.h
new file mode 100644
index 000000000000..38c061104ecd
--- /dev/null
+++ b/arch/arm/include/asm/arch-rockchip/cru_rk3506.h
@@ -0,0 +1,220 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023 Rockchip Electronics Co., Ltd.
+ * Author: Finley Xiao <finley.xiao@rock-chips.com>
+ */
+
+#ifndef _ASM_ARCH_CRU_RK3506_H
+#define _ASM_ARCH_CRU_RK3506_H
+
+#include <linux/bitops.h>
+#include <linux/bitfield.h>
+
+#define MHz 1000000
+#define KHz 1000
+#define OSC_HZ (24 * MHz)
+
+/* RK3506 pll id */
+enum rk3506_pll_id {
+ GPLL,
+ V0PLL,
+ V1PLL,
+ PLL_COUNT,
+};
+
+struct rk3506_clk_priv {
+ struct rk3506_cru *cru;
+ unsigned long gpll_hz;
+ unsigned long gpll_div_hz;
+ unsigned long gpll_div_100mhz;
+ unsigned long v0pll_hz;
+ unsigned long v0pll_div_hz;
+ unsigned long v1pll_hz;
+ unsigned long v1pll_div_hz;
+ unsigned long armclk_hz;
+ unsigned long armclk_enter_hz;
+ unsigned long armclk_init_hz;
+ bool sync_kernel;
+};
+
+#define RK3506_CRU_BASE ((struct rk3506_cru *)0xff9a0000)
+
+struct rk3506_cru {
+ /* cru */
+ unsigned int reserved0000[160]; /* offset 0x0 */
+ unsigned int mode_con; /* offset 0x280 */
+ unsigned int reserved0284[31]; /* offset 0x284 */
+ unsigned int clksel_con[62]; /* offset 0x300 */
+ unsigned int reserved03f8[258]; /* offset 0x3F8 */
+ unsigned int gate_con[23]; /* offset 0x800 */
+ unsigned int reserved085c[105]; /* offset 0x85C */
+ unsigned int softrst_con[23]; /* offset 0xA00 */
+ unsigned int reserved0a5c[105]; /* offset 0xA5C */
+ unsigned int glb_cnt_th; /* offset 0xC00 */
+ unsigned int glb_rst_st; /* offset 0xC04 */
+ unsigned int glb_srst_fst; /* offset 0xC08 */
+ unsigned int glb_srst_snd; /* offset 0xC0C */
+ unsigned int glb_rst_con; /* offset 0xC10 */
+ unsigned int reserved0c14[6]; /* offset 0xC14 */
+ unsigned int corewfi_con; /* offset 0xC2C */
+ unsigned int reserved0c30[15604]; /* offset 0xC30 */
+
+ /* pmu cru */
+ unsigned int gpll_con[5]; /* offset 0x10000 */
+ unsigned int reserved10014[3]; /* offset 0x10014 */
+ unsigned int v0pll_con[5]; /* offset 0x10020 */
+ unsigned int reserved10034[3]; /* offset 0x10034 */
+ unsigned int v1pll_con[5]; /* offset 0x10040 */
+ unsigned int reserved10074[171]; /* offset 0x10054 */
+ unsigned int pmuclksel_con[7]; /* offset 0x10300 */
+ unsigned int reserved1031c[313]; /* offset 0x1031C */
+ unsigned int pmugate_con[3]; /* offset 0x10800 */
+ unsigned int reserved1080c[125]; /* offset 0x1080C */
+ unsigned int pmusoftrst_con[2]; /* offset 0x10A00 */
+ unsigned int reserved10a08[7583]; /* offset 0x10A08 */
+};
+
+check_member(rk3506_cru, reserved0c30[0], 0x0c30);
+check_member(rk3506_cru, reserved10a08[0], 0x10a08);
+
+struct pll_rate_table {
+ unsigned long rate;
+ unsigned int fbdiv;
+ unsigned int postdiv1;
+ unsigned int refdiv;
+ unsigned int postdiv2;
+ unsigned int dsmpd;
+ unsigned int frac;
+};
+
+#define RK3506_PMU_CRU_BASE 0x10000
+#define RK3506_PLL_CON(x) ((x) * 0x4 + RK3506_PMU_CRU_BASE)
+#define RK3506_CLKSEL_CON(x) ((x) * 0x4 + 0x300)
+#define RK3506_MODE_CON 0x280
+
+enum {
+ /* CRU_CLKSEL_CON00 */
+ CLK_GPLL_DIV_MASK = GENMASK(9, 6),
+ CLK_GPLL_DIV_100M_MASK = GENMASK(13, 10),
+
+ /* CRU_CLKSEL_CON01 */
+ CLK_V0PLL_DIV_MASK = GENMASK(3, 0),
+ CLK_V1PLL_DIV_MASK = GENMASK(7, 4),
+
+ /* CRU_CLKSEL_CON15 */
+ CLK_CORE_SRC_DIV_MASK = GENMASK(4, 0),
+ CLK_CORE_SRC_SEL_MASK = GENMASK(6, 5),
+ CLK_CORE_SEL_GPLL = 0,
+ CLK_CORE_SEL_V0PLL,
+ CLK_CORE_SEL_V1PLL,
+
+ ACLK_CORE_DIV_MASK = GENMASK(12, 9),
+
+ /* CRU_CLKSEL_CON16 */
+ PCLK_CORE_DIV_MASK = GENMASK(3, 0),
+
+ /* CRU_CLKSEL_CON21 */
+ ACLK_BUS_DIV_MASK = GENMASK(4, 0),
+ ACLK_BUS_SEL_MASK = GENMASK(6, 5),
+ ACLK_BUS_SEL_GPLL_DIV = 0,
+ ACLK_BUS_SEL_V0PLL_DIV,
+ ACLK_BUS_SEL_V1PLL_DIV,
+
+ HCLK_BUS_DIV_MASK = GENMASK(11, 7),
+ HCLK_BUS_SEL_MASK = GENMASK(13, 12),
+
+ /* CRU_CLKSEL_CON22 */
+ PCLK_BUS_DIV_MASK = GENMASK(4, 0),
+ PCLK_BUS_SEL_MASK = GENMASK(6, 5),
+
+ /* CRU_CLKSEL_CON29 */
+ HCLK_LSPERI_DIV_MASK = GENMASK(4, 0),
+ HCLK_LSPERI_SEL_MASK = GENMASK(6, 5),
+
+ /* CRU_CLKSEL_CON32 */
+ CLK_I2C0_DIV_MASK = GENMASK(3, 0),
+ CLK_I2C0_SEL_MASK = GENMASK(5, 4),
+ CLK_I2C_SEL_GPLL = 0,
+ CLK_I2C_SEL_V0PLL,
+ CLK_I2C_SEL_V1PLL,
+ CLK_I2C1_DIV_MASK = GENMASK(9, 6),
+ CLK_I2C1_SEL_MASK = GENMASK(11, 10),
+
+ /* CRU_CLKSEL_CON33 */
+ CLK_I2C2_DIV_MASK = GENMASK(3, 0),
+ CLK_I2C2_SEL_MASK = GENMASK(5, 4),
+ CLK_PWM1_DIV_MASK = GENMASK(9, 6),
+ CLK_PWM1_SEL_MASK = GENMASK(11, 10),
+ CLK_PWM1_SEL_GPLL_DIV = 0,
+ CLK_PWM1_SEL_V0PLL_DIV,
+ CLK_PWM1_SEL_V1PLL_DIV,
+
+ /* CRU_CLKSEL_CON34 */
+ CLK_SPI0_DIV_MASK = GENMASK(7, 4),
+ CLK_SPI0_SEL_MASK = GENMASK(9, 8),
+ CLK_SPI_SEL_24M = 0,
+ CLK_SPI_SEL_GPLL_DIV,
+ CLK_SPI_SEL_V0PLL_DIV,
+ CLK_SPI_SEL_V1PLL_DIV,
+ CLK_SPI1_DIV_MASK = GENMASK(13, 10),
+ CLK_SPI1_SEL_MASK = GENMASK(15, 14),
+
+ /* CRU_CLKSEL_CON49 */
+ ACLK_HSPERI_DIV_MASK = GENMASK(4, 0),
+ ACLK_HSPERI_SEL_MASK = GENMASK(6, 5),
+ ACLK_HSPERI_SEL_GPLL_DIV = 0,
+ ACLK_HSPERI_SEL_V0PLL_DIV,
+ ACLK_HSPERI_SEL_V1PLL_DIV,
+
+ CCLK_SDMMC_DIV_MASK = GENMASK(12, 7),
+ CCLK_SDMMC_SEL_MASK = GENMASK(14, 13),
+ CCLK_SDMMC_SEL_24M = 0,
+ CCLK_SDMMC_SEL_GPLL,
+ CCLK_SDMMC_SEL_V0PLL,
+ CCLK_SDMMC_SEL_V1PLL,
+
+ /* CRU_CLKSEL_CON50 */
+ SCLK_FSPI_DIV_MASK = GENMASK(4, 0),
+ SCLK_FSPI_SEL_MASK = GENMASK(6, 5),
+ SCLK_FSPI_SEL_24M = 0,
+ SCLK_FSPI_SEL_GPLL,
+ SCLK_FSPI_SEL_V0PLL,
+ SCLK_FSPI_SEL_V1PLL,
+ CLK_MAC_DIV_MASK = GENMASK(11, 7),
+
+ /* CRU_CLKSEL_CON54 */
+ CLK_SARADC_DIV_MASK = GENMASK(3, 0),
+ CLK_SARADC_SEL_MASK = GENMASK(5, 4),
+ CLK_SARADC_SEL_24M = 0,
+ CLK_SARADC_SEL_400K,
+ CLK_SARADC_SEL_32K,
+
+ /* CRU_CLKSEL_CON60 */
+ DCLK_VOP_DIV_MASK = GENMASK(7, 0),
+ DCLK_VOP_SEL_MASK = GENMASK(10, 8),
+ DCLK_VOP_SEL_24M = 0,
+ DCLK_VOP_SEL_GPLL,
+ DCLK_VOP_SEL_V0PLL,
+ DCLK_VOP_SEL_V1PLL,
+ DCLK_VOP_SEL_FRAC_VOIC1,
+ DCLK_VOP_SEL_FRAC_COMMON0,
+ DCLK_VOP_SEL_FRAC_COMMON1,
+ DCLK_VOP_SEL_FRAC_COMMON2,
+
+ /* CRU_CLKSEL_CON61 */
+ CLK_TSADC_DIV_MASK = GENMASK(7, 0),
+ CLK_TSADC_TSEN_DIV_MASK = GENMASK(10, 8),
+
+ /* PMUCRU_CLKSEL_CON00 */
+ CLK_PWM0_DIV_MASK = GENMASK(9, 6),
+ CLK_MAC_OUT_DIV_MASK = GENMASK(15, 10),
+
+ /* SCRU_CLKSEL_CON104 */
+ CLK_PKA_CRYPTO_DIV_MASK = GENMASK(11, 7),
+ CLK_PKA_CRYPTO_SEL_MASK = GENMASK(13, 12),
+ CLK_PKA_CRYPTO_SEL_GPLL = 0,
+ CLK_PKA_CRYPTO_SEL_V0PLL,
+ CLK_PKA_CRYPTO_SEL_V1PLL,
+};
+
+#endif /* _ASM_ARCH_CRU_RK3506_H */
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index 34b63d4df34a..07525c364326 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_ROCKCHIP_RK3308) += clk_rk3308.o
obj-$(CONFIG_ROCKCHIP_RK3328) += clk_rk3328.o
obj-$(CONFIG_ROCKCHIP_RK3368) += clk_rk3368.o
obj-$(CONFIG_ROCKCHIP_RK3399) += clk_rk3399.o
+obj-$(CONFIG_ROCKCHIP_RK3506) += clk_rk3506.o
obj-$(CONFIG_ROCKCHIP_RK3528) += clk_rk3528.o
obj-$(CONFIG_ROCKCHIP_RK3568) += clk_rk3568.o
obj-$(CONFIG_ROCKCHIP_RK3576) += clk_rk3576.o
diff --git a/drivers/clk/rockchip/clk_rk3506.c b/drivers/clk/rockchip/clk_rk3506.c
new file mode 100644
index 000000000000..36a80d7dfbde
--- /dev/null
+++ b/drivers/clk/rockchip/clk_rk3506.c
@@ -0,0 +1,1212 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 Rockchip Electronics Co., Ltd.
+ * Author: Finley Xiao <finley.xiao@rock-chips.com>
+ */
+
+#include <bitfield.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <syscon.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru_rk3506.h>
+#include <asm/arch-rockchip/hardware.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dt-bindings/clock/rockchip,rk3506-cru.h>
+#include <linux/delay.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define RK3506_SCRU_BASE 0xff9a8000
+
+#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
+
+/*
+ * [FRAC PLL]: GPLL, V0PLL, V1PLL
+ * - VCO Frequency: 950MHz to 3800MHZ
+ * - Output Frequency: 19MHz to 3800MHZ
+ * - refdiv: 1 to 63 (Int Mode), 1 to 2 (Frac Mode)
+ * - fbdiv: 16 to 3800 (Int Mode), 20 to 380 (Frac Mode)
+ * - post1div: 1 to 7
+ * - post2div: 1 to 7
+ */
+static struct rockchip_pll_rate_table rk3506_pll_rates[] = {
+ /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
+ RK3036_PLL_RATE(1896000000, 1, 79, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1800000000, 1, 75, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1704000000, 1, 71, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1500000000, 1, 125, 2, 1, 1, 0),
+ RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1350000000, 4, 225, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
+ RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0),
+ RK3036_PLL_RATE(1179648000, 1, 49, 1, 1, 0, 2550137),
+ RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
+ RK3036_PLL_RATE(1000000000, 3, 125, 1, 1, 1, 0),
+ RK3036_PLL_RATE(993484800, 1, 41, 1, 1, 0, 6630355),
+ RK3036_PLL_RATE(983040000, 1, 40, 1, 1, 0, 16106127),
+ RK3036_PLL_RATE(960000000, 1, 80, 2, 1, 1, 0),
+ RK3036_PLL_RATE(912000000, 1, 76, 2, 1, 1, 0),
+ RK3036_PLL_RATE(903168000, 1, 75, 2, 1, 0, 4429185),
+ RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
+ RK3036_PLL_RATE(800000000, 3, 200, 2, 1, 1, 0),
+ RK3036_PLL_RATE(600000000, 1, 50, 2, 1, 1, 0),
+ RK3036_PLL_RATE(594000000, 2, 99, 2, 1, 1, 0),
+ RK3036_PLL_RATE(408000000, 1, 68, 2, 2, 1, 0),
+ RK3036_PLL_RATE(312000000, 1, 78, 6, 1, 1, 0),
+ RK3036_PLL_RATE(216000000, 1, 72, 4, 2, 1, 0),
+ RK3036_PLL_RATE(96000000, 1, 48, 6, 2, 1, 0),
+ { /* sentinel */ },
+};
+
+static struct rockchip_pll_clock rk3506_pll_clks[] = {
+ [GPLL] = PLL(pll_rk3328, PLL_GPLL, RK3506_PLL_CON(0),
+ RK3506_MODE_CON, 0, 10, 0, rk3506_pll_rates),
+ [V0PLL] = PLL(pll_rk3328, PLL_V0PLL, RK3506_PLL_CON(8),
+ RK3506_MODE_CON, 2, 10, 0, rk3506_pll_rates),
+ [V1PLL] = PLL(pll_rk3328, PLL_V1PLL, RK3506_PLL_CON(16),
+ RK3506_MODE_CON, 4, 10, 0, rk3506_pll_rates),
+};
+
+#define RK3506_CPUCLK_RATE(_rate, _aclk_m_core, _pclk_dbg) \
+{ \
+ .rate = _rate##U, \
+ .aclk_div = (_aclk_m_core), \
+ .pclk_div = (_pclk_dbg), \
+}
+
+/* SIGN-OFF: aclk_core: 500M, pclk_core: 125M, */
+static struct rockchip_cpu_rate_table rk3506_cpu_rates[] = {
+ RK3506_CPUCLK_RATE(1179648000, 1, 6),
+ RK3506_CPUCLK_RATE(903168000, 1, 5),
+ RK3506_CPUCLK_RATE(800000000, 1, 4),
+ RK3506_CPUCLK_RATE(589824000, 1, 3),
+ RK3506_CPUCLK_RATE(400000000, 1, 2),
+ RK3506_CPUCLK_RATE(200000000, 1, 1),
+ { /* sentinel */ },
+};
+
+static int rk3506_armclk_get_rate(struct rk3506_clk_priv *priv)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 con, div, sel;
+ ulong prate;
+
+ con = readl(&cru->clksel_con[15]);
+ sel = FIELD_GET(CLK_CORE_SRC_SEL_MASK, con);
+ div = FIELD_GET(CLK_CORE_SRC_DIV_MASK, con);
+
+ if (sel == CLK_CORE_SEL_GPLL)
+ prate = priv->gpll_hz;
+ else if (sel == CLK_CORE_SEL_V0PLL)
+ prate = priv->v0pll_hz;
+ else if (sel == CLK_CORE_SEL_V1PLL)
+ prate = priv->v1pll_hz;
+ else
+ return -EINVAL;
+
+ return DIV_TO_RATE(prate, div);
+}
+
+static int rk3506_armclk_set_rate(struct rk3506_clk_priv *priv, ulong new_rate)
+{
+ const struct rockchip_cpu_rate_table *rate;
+ struct rk3506_cru *cru = priv->cru;
+ u32 con, div, old_div, sel;
+ ulong old_rate, prate;
+
+ rate = rockchip_get_cpu_settings(rk3506_cpu_rates, new_rate);
+ if (!rate) {
+ printf("%s unsupported rate\n", __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * set up dependent divisors for PCLK and ACLK clocks.
+ */
+ old_rate = rk3506_armclk_get_rate(priv);
+ if (new_rate >= old_rate) {
+ rk_clrsetreg(&cru->clksel_con[15], ACLK_CORE_DIV_MASK,
+ FIELD_PREP(ACLK_CORE_DIV_MASK, rate->aclk_div));
+ rk_clrsetreg(&cru->clksel_con[16], PCLK_CORE_DIV_MASK,
+ FIELD_PREP(PCLK_CORE_DIV_MASK, rate->pclk_div));
+ }
+
+ if (new_rate == 589824000 || new_rate == 1179648000) {
+ sel = CLK_CORE_SEL_V0PLL;
+ div = DIV_ROUND_UP(priv->v0pll_hz, new_rate);
+ prate = priv->v0pll_hz;
+ } else if (new_rate == 903168000) {
+ sel = CLK_CORE_SEL_V1PLL;
+ div = DIV_ROUND_UP(priv->v1pll_hz, new_rate);
+ prate = priv->v1pll_hz;
+ } else {
+ sel = CLK_CORE_SEL_GPLL;
+ div = DIV_ROUND_UP(priv->gpll_hz, new_rate);
+ prate = priv->gpll_hz;
+ }
+ assert(div - 1 <= 31);
+
+ con = readl(&cru->clksel_con[15]);
+ old_div = FIELD_GET(CLK_CORE_SRC_DIV_MASK, con);
+ if (DIV_TO_RATE(prate, old_div) > new_rate) {
+ rk_clrsetreg(&cru->clksel_con[15], CLK_CORE_SRC_DIV_MASK,
+ FIELD_PREP(CLK_CORE_SRC_DIV_MASK, div - 1));
+ rk_clrsetreg(&cru->clksel_con[15], CLK_CORE_SRC_SEL_MASK,
+ FIELD_PREP(CLK_CORE_SRC_SEL_MASK, sel));
+ } else {
+ rk_clrsetreg(&cru->clksel_con[15], CLK_CORE_SRC_SEL_MASK,
+ FIELD_PREP(CLK_CORE_SRC_SEL_MASK, sel));
+ rk_clrsetreg(&cru->clksel_con[15], CLK_CORE_SRC_DIV_MASK,
+ FIELD_PREP(CLK_CORE_SRC_DIV_MASK, div - 1));
+ }
+
+ if (new_rate < old_rate) {
+ rk_clrsetreg(&cru->clksel_con[15], ACLK_CORE_DIV_MASK,
+ FIELD_PREP(ACLK_CORE_DIV_MASK, rate->aclk_div));
+ rk_clrsetreg(&cru->clksel_con[16], PCLK_CORE_DIV_MASK,
+ FIELD_PREP(PCLK_CORE_DIV_MASK, rate->pclk_div));
+ }
+
+ return 0;
+}
+
+static ulong rk3506_pll_div_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 con, div;
+ ulong prate;
+
+ switch (clk_id) {
+ case CLK_GPLL_DIV:
+ con = readl(&cru->clksel_con[0]);
+ div = FIELD_GET(CLK_GPLL_DIV_MASK, con);
+ prate = priv->gpll_hz;
+ break;
+ case CLK_GPLL_DIV_100M:
+ con = readl(&cru->clksel_con[0]);
+ div = FIELD_GET(CLK_GPLL_DIV_100M_MASK, con);
+ prate = priv->gpll_div_hz;
+ break;
+ case CLK_V0PLL_DIV:
+ con = readl(&cru->clksel_con[1]);
+ div = FIELD_GET(CLK_V0PLL_DIV_MASK, con);
+ prate = priv->v0pll_hz;
+ break;
+ case CLK_V1PLL_DIV:
+ con = readl(&cru->clksel_con[1]);
+ div = FIELD_GET(CLK_V1PLL_DIV_MASK, con);
+ prate = priv->v1pll_hz;
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return DIV_TO_RATE(prate, div);
+}
+
+static ulong rk3506_pll_div_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
+ ulong rate)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 div;
+
+ switch (clk_id) {
+ case CLK_GPLL_DIV:
+ div = DIV_ROUND_UP(priv->gpll_hz, rate);
+ assert(div - 1 <= 15);
+ rk_clrsetreg(&cru->clksel_con[0], CLK_GPLL_DIV_MASK,
+ FIELD_PREP(CLK_GPLL_DIV_MASK, div - 1));
+ break;
+ case CLK_GPLL_DIV_100M:
+ div = DIV_ROUND_UP(priv->gpll_div_hz, rate);
+ assert(div - 1 <= 15);
+ rk_clrsetreg(&cru->clksel_con[0], CLK_GPLL_DIV_100M_MASK,
+ FIELD_PREP(CLK_GPLL_DIV_100M_MASK, div - 1));
+ break;
+ case CLK_V0PLL_DIV:
+ div = DIV_ROUND_UP(priv->v0pll_hz, rate);
+ assert(div - 1 <= 15);
+ rk_clrsetreg(&cru->clksel_con[1], CLK_V0PLL_DIV_MASK,
+ FIELD_PREP(CLK_V0PLL_DIV_MASK, div - 1));
+ break;
+ case CLK_V1PLL_DIV:
+ div = DIV_ROUND_UP(priv->v1pll_hz, rate);
+ assert(div - 1 <= 15);
+ rk_clrsetreg(&cru->clksel_con[1], CLK_V1PLL_DIV_MASK,
+ FIELD_PREP(CLK_V1PLL_DIV_MASK, div - 1));
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return rk3506_pll_div_get_rate(priv, clk_id);
+}
+
+static ulong rk3506_bus_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 con, div, sel;
+ ulong prate;
+
+ switch (clk_id) {
+ case ACLK_BUS_ROOT:
+ con = readl(&cru->clksel_con[21]);
+ sel = FIELD_GET(ACLK_BUS_SEL_MASK, con);
+ div = FIELD_GET(ACLK_BUS_DIV_MASK, con);
+ break;
+ case HCLK_BUS_ROOT:
+ con = readl(&cru->clksel_con[21]);
+ sel = FIELD_GET(HCLK_BUS_SEL_MASK, con);
+ div = FIELD_GET(HCLK_BUS_DIV_MASK, con);
+ break;
+ case PCLK_BUS_ROOT:
+ con = readl(&cru->clksel_con[22]);
+ sel = FIELD_GET(PCLK_BUS_SEL_MASK, con);
+ div = FIELD_GET(PCLK_BUS_DIV_MASK, con);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ if (sel == ACLK_BUS_SEL_GPLL_DIV)
+ prate = priv->gpll_div_hz;
+ else if (sel == ACLK_BUS_SEL_V0PLL_DIV)
+ prate = priv->v0pll_div_hz;
+ else if (sel == ACLK_BUS_SEL_V1PLL_DIV)
+ prate = priv->v1pll_div_hz;
+ else
+ return -EINVAL;
+
+ return DIV_TO_RATE(prate, div);
+}
+
+static ulong rk3506_bus_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
+ ulong rate)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 div, sel;
+
+ if (priv->v0pll_div_hz % rate == 0) {
+ sel = ACLK_BUS_SEL_V0PLL_DIV;
+ div = DIV_ROUND_UP(priv->v0pll_div_hz, rate);
+ } else if (priv->v1pll_div_hz % rate == 0) {
+ sel = ACLK_BUS_SEL_V1PLL_DIV;
+ div = DIV_ROUND_UP(priv->v1pll_div_hz, rate);
+ } else {
+ sel = ACLK_BUS_SEL_GPLL_DIV;
+ div = DIV_ROUND_UP(priv->gpll_div_hz, rate);
+ }
+ assert(div - 1 <= 31);
+
+ switch (clk_id) {
+ case ACLK_BUS_ROOT:
+ rk_clrsetreg(&cru->clksel_con[21],
+ ACLK_BUS_SEL_MASK | ACLK_BUS_DIV_MASK,
+ FIELD_PREP(ACLK_BUS_SEL_MASK, sel) |
+ FIELD_PREP(ACLK_BUS_DIV_MASK, div - 1));
+ break;
+ case HCLK_BUS_ROOT:
+ rk_clrsetreg(&cru->clksel_con[21],
+ HCLK_BUS_SEL_MASK | HCLK_BUS_DIV_MASK,
+ FIELD_PREP(HCLK_BUS_SEL_MASK, sel) |
+ FIELD_PREP(HCLK_BUS_DIV_MASK, div - 1));
+ break;
+ case PCLK_BUS_ROOT:
+ rk_clrsetreg(&cru->clksel_con[22],
+ PCLK_BUS_SEL_MASK | PCLK_BUS_DIV_MASK,
+ FIELD_PREP(PCLK_BUS_SEL_MASK, sel) |
+ FIELD_PREP(PCLK_BUS_DIV_MASK, div - 1));
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return rk3506_bus_get_rate(priv, clk_id);
+}
+
+static ulong rk3506_peri_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 con, div, sel;
+ ulong prate;
+
+ switch (clk_id) {
+ case ACLK_HSPERI_ROOT:
+ con = readl(&cru->clksel_con[49]);
+ sel = FIELD_GET(ACLK_HSPERI_SEL_MASK, con);
+ div = FIELD_GET(ACLK_HSPERI_DIV_MASK, con);
+ break;
+ case HCLK_LSPERI_ROOT:
+ con = readl(&cru->clksel_con[29]);
+ sel = FIELD_GET(HCLK_LSPERI_SEL_MASK, con);
+ div = FIELD_GET(HCLK_LSPERI_DIV_MASK, con);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ if (sel == ACLK_HSPERI_SEL_GPLL_DIV)
+ prate = priv->gpll_div_hz;
+ else if (sel == ACLK_HSPERI_SEL_V0PLL_DIV)
+ prate = priv->v0pll_div_hz;
+ else if (sel == ACLK_HSPERI_SEL_V1PLL_DIV)
+ prate = priv->v1pll_div_hz;
+ else
+ return -EINVAL;
+
+ return DIV_TO_RATE(prate, div);
+}
+
+static ulong rk3506_peri_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
+ ulong rate)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 div, sel;
+
+ if (priv->v0pll_div_hz % rate == 0) {
+ sel = ACLK_BUS_SEL_V0PLL_DIV;
+ div = DIV_ROUND_UP(priv->v0pll_div_hz, rate);
+ } else if (priv->v1pll_div_hz % rate == 0) {
+ sel = ACLK_BUS_SEL_V1PLL_DIV;
+ div = DIV_ROUND_UP(priv->v1pll_div_hz, rate);
+ } else {
+ sel = ACLK_BUS_SEL_GPLL_DIV;
+ div = DIV_ROUND_UP(priv->gpll_div_hz, rate);
+ }
+ assert(div - 1 <= 31);
+
+ switch (clk_id) {
+ case ACLK_HSPERI_ROOT:
+ rk_clrsetreg(&cru->clksel_con[49],
+ ACLK_HSPERI_SEL_MASK | ACLK_HSPERI_DIV_MASK,
+ FIELD_PREP(ACLK_HSPERI_SEL_MASK, sel) |
+ FIELD_PREP(ACLK_HSPERI_DIV_MASK, div - 1));
+ break;
+ case HCLK_LSPERI_ROOT:
+ rk_clrsetreg(&cru->clksel_con[29],
+ HCLK_LSPERI_SEL_MASK | HCLK_LSPERI_DIV_MASK,
+ FIELD_PREP(HCLK_LSPERI_SEL_MASK, sel) |
+ FIELD_PREP(HCLK_LSPERI_DIV_MASK, div - 1));
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return rk3506_peri_get_rate(priv, clk_id);
+}
+
+static ulong rk3506_sdmmc_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 con, div, sel;
+ ulong prate;
+
+ con = readl(&cru->clksel_con[49]);
+ sel = FIELD_GET(CCLK_SDMMC_SEL_MASK, con);
+ div = FIELD_GET(CCLK_SDMMC_DIV_MASK, con);
+
+ if (sel == CCLK_SDMMC_SEL_24M)
+ prate = OSC_HZ;
+ else if (sel == CCLK_SDMMC_SEL_GPLL)
+ prate = priv->gpll_hz;
+ else if (sel == CCLK_SDMMC_SEL_V0PLL)
+ prate = priv->v0pll_hz;
+ else if (sel == CCLK_SDMMC_SEL_V1PLL)
+ prate = priv->v1pll_hz;
+ else
+ return -EINVAL;
+
+ return DIV_TO_RATE(prate, div);
+}
+
+static ulong rk3506_sdmmc_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
+ ulong rate)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 div, sel;
+
+ if (OSC_HZ % rate == 0) {
+ sel = CCLK_SDMMC_SEL_24M;
+ div = DIV_ROUND_UP(OSC_HZ, rate);
+ } else if (priv->v0pll_hz % rate == 0) {
+ sel = CCLK_SDMMC_SEL_V0PLL;
+ div = DIV_ROUND_UP(priv->v0pll_hz, rate);
+ } else if (priv->v1pll_hz % rate == 0) {
+ sel = CCLK_SDMMC_SEL_V1PLL;
+ div = DIV_ROUND_UP(priv->v1pll_hz, rate);
+ } else {
+ sel = CCLK_SDMMC_SEL_GPLL;
+ div = DIV_ROUND_UP(priv->gpll_hz, rate);
+ }
+ assert(div - 1 <= 63);
+
+ rk_clrsetreg(&cru->clksel_con[49],
+ CCLK_SDMMC_SEL_MASK | CCLK_SDMMC_DIV_MASK,
+ FIELD_PREP(CCLK_SDMMC_SEL_MASK, sel) |
+ FIELD_PREP(CCLK_SDMMC_DIV_MASK, div - 1));
+
+ return rk3506_sdmmc_get_rate(priv, clk_id);
+}
+
+static ulong rk3506_saradc_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 con, div, sel;
+ ulong prate;
+
+ con = readl(&cru->clksel_con[54]);
+ sel = FIELD_GET(CLK_SARADC_SEL_MASK, con);
+ div = FIELD_GET(CLK_SARADC_DIV_MASK, con);
+
+ if (sel == CLK_SARADC_SEL_24M)
+ prate = OSC_HZ;
+ else if (sel == CLK_SARADC_SEL_400K)
+ prate = 400000;
+ else if (sel == CLK_SARADC_SEL_32K)
+ prate = 32000;
+ else
+ return -EINVAL;
+
+ return DIV_TO_RATE(prate, div);
+}
+
+static ulong rk3506_saradc_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
+ ulong rate)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 div, sel;
+
+ if (32000 % rate == 0) {
+ sel = CLK_SARADC_SEL_32K;
+ div = 1;
+ } else if (400000 % rate == 0) {
+ sel = CLK_SARADC_SEL_400K;
+ div = 1;
+ } else {
+ sel = CLK_SARADC_SEL_24M;
+ div = DIV_ROUND_UP(OSC_HZ, rate);
+ }
+ assert(div - 1 <= 15);
+
+ rk_clrsetreg(&cru->clksel_con[54],
+ CLK_SARADC_SEL_MASK | CLK_SARADC_DIV_MASK,
+ FIELD_PREP(CLK_SARADC_SEL_MASK, sel) |
+ FIELD_PREP(CLK_SARADC_DIV_MASK, div - 1));
+
+ return rk3506_saradc_get_rate(priv, clk_id);
+}
+
+static ulong rk3506_tsadc_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 con, div;
+
+ con = readl(&cru->clksel_con[61]);
+ switch (clk_id) {
+ case CLK_TSADC_TSEN:
+ div = FIELD_GET(CLK_TSADC_TSEN_DIV_MASK, con);
+ break;
+ case CLK_TSADC:
+ div = FIELD_GET(CLK_TSADC_DIV_MASK, con);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return DIV_TO_RATE(OSC_HZ, div);
+}
+
+static ulong rk3506_tsadc_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
+ ulong rate)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 div;
+
+ switch (clk_id) {
+ case CLK_TSADC_TSEN:
+ div = DIV_ROUND_UP(OSC_HZ, rate);
+ assert(div - 1 <= 7);
+ rk_clrsetreg(&cru->clksel_con[61], CLK_TSADC_TSEN_DIV_MASK,
+ FIELD_PREP(CLK_TSADC_TSEN_DIV_MASK, div - 1));
+ break;
+ case CLK_TSADC:
+ div = DIV_ROUND_UP(OSC_HZ, rate);
+ assert(div - 1 <= 255);
+ rk_clrsetreg(&cru->clksel_con[61], CLK_TSADC_DIV_MASK,
+ FIELD_PREP(CLK_TSADC_DIV_MASK, div - 1));
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return rk3506_tsadc_get_rate(priv, clk_id);
+}
+
+static ulong rk3506_i2c_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 con, div, sel;
+ ulong prate;
+
+ switch (clk_id) {
+ case CLK_I2C0:
+ con = readl(&cru->clksel_con[32]);
+ sel = FIELD_GET(CLK_I2C0_SEL_MASK, con);
+ div = FIELD_GET(CLK_I2C0_DIV_MASK, con);
+ case CLK_I2C1:
+ con = readl(&cru->clksel_con[32]);
+ sel = FIELD_GET(CLK_I2C1_SEL_MASK, con);
+ div = FIELD_GET(CLK_I2C1_DIV_MASK, con);
+ case CLK_I2C2:
+ con = readl(&cru->clksel_con[33]);
+ sel = FIELD_GET(CLK_I2C2_SEL_MASK, con);
+ div = FIELD_GET(CLK_I2C2_DIV_MASK, con);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ if (sel == CLK_I2C_SEL_GPLL)
+ prate = priv->gpll_hz;
+ else if (sel == CLK_I2C_SEL_V0PLL)
+ prate = priv->v0pll_hz;
+ else if (sel == CLK_I2C_SEL_V1PLL)
+ prate = priv->v1pll_hz;
+ else
+ return -EINVAL;
+
+ return DIV_TO_RATE(prate, div);
+}
+
+static ulong rk3506_i2c_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
+ ulong rate)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 div, sel;
+
+ if (priv->v0pll_hz % rate == 0) {
+ sel = CLK_I2C_SEL_V0PLL;
+ div = DIV_ROUND_UP(priv->v0pll_hz, rate);
+ } else if (priv->v1pll_hz % rate == 0) {
+ sel = CLK_I2C_SEL_V1PLL;
+ div = DIV_ROUND_UP(priv->v1pll_hz, rate);
+ } else {
+ sel = CLK_I2C_SEL_GPLL;
+ div = DIV_ROUND_UP(priv->gpll_hz, rate);
+ }
+ assert(div - 1 <= 15);
+
+ switch (clk_id) {
+ case CLK_I2C0:
+ rk_clrsetreg(&cru->clksel_con[32],
+ CLK_I2C0_SEL_MASK | CLK_I2C0_DIV_MASK,
+ FIELD_PREP(CLK_I2C0_SEL_MASK, sel) |
+ FIELD_PREP(CLK_I2C0_DIV_MASK, div - 1));
+ break;
+ case CLK_I2C1:
+ rk_clrsetreg(&cru->clksel_con[32],
+ CLK_I2C1_SEL_MASK | CLK_I2C1_DIV_MASK,
+ FIELD_PREP(CLK_I2C1_SEL_MASK, sel) |
+ FIELD_PREP(CLK_I2C1_DIV_MASK, div - 1));
+ break;
+ case CLK_I2C2:
+ rk_clrsetreg(&cru->clksel_con[33],
+ CLK_I2C2_SEL_MASK | CLK_I2C2_DIV_MASK,
+ FIELD_PREP(CLK_I2C2_SEL_MASK, sel) |
+ FIELD_PREP(CLK_I2C2_DIV_MASK, div - 1));
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return rk3506_i2c_get_rate(priv, clk_id);
+}
+
+static ulong rk3506_pwm_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 con, div, sel;
+ ulong prate;
+
+ switch (clk_id) {
+ case CLK_PWM0:
+ con = readl(&cru->pmuclksel_con[0]);
+ div = FIELD_GET(CLK_PWM0_DIV_MASK, con);
+ prate = priv->gpll_div_100mhz;
+ break;
+ case CLK_PWM1:
+ con = readl(&cru->clksel_con[33]);
+ sel = FIELD_GET(CLK_PWM1_SEL_MASK, con);
+ div = FIELD_GET(CLK_PWM1_DIV_MASK, con);
+ if (sel == CLK_PWM1_SEL_GPLL_DIV)
+ prate = priv->gpll_div_hz;
+ else if (sel == CLK_PWM1_SEL_V0PLL_DIV)
+ prate = priv->v0pll_div_hz;
+ else if (sel == CLK_PWM1_SEL_V1PLL_DIV)
+ prate = priv->v1pll_div_hz;
+ else
+ return -EINVAL;
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return DIV_TO_RATE(prate, div);
+}
+
+static ulong rk3506_pwm_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
+ ulong rate)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 div, sel;
+
+ switch (clk_id) {
+ case CLK_PWM0:
+ div = DIV_ROUND_UP(priv->gpll_div_100mhz, rate);
+ assert(div - 1 <= 15);
+ rk_clrsetreg(&cru->pmuclksel_con[0], CLK_PWM0_DIV_MASK,
+ FIELD_PREP(CLK_PWM0_DIV_MASK, div - 1));
+ break;
+ case CLK_PWM1:
+ if (priv->v0pll_hz % rate == 0) {
+ sel = CLK_PWM1_SEL_V0PLL_DIV;
+ div = DIV_ROUND_UP(priv->v0pll_div_hz, rate);
+ } else if (priv->v1pll_hz % rate == 0) {
+ sel = CLK_PWM1_SEL_V1PLL_DIV;
+ div = DIV_ROUND_UP(priv->v1pll_div_hz, rate);
+ } else {
+ sel = CLK_PWM1_SEL_GPLL_DIV;
+ div = DIV_ROUND_UP(priv->gpll_div_hz, rate);
+ }
+ assert(div - 1 <= 15);
+ rk_clrsetreg(&cru->clksel_con[33],
+ CLK_PWM1_SEL_MASK | CLK_PWM1_DIV_MASK,
+ FIELD_PREP(CLK_PWM1_SEL_MASK, sel) |
+ FIELD_PREP(CLK_PWM1_DIV_MASK, div - 1));
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return rk3506_pwm_get_rate(priv, clk_id);
+}
+
+static ulong rk3506_spi_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 con, div, sel;
+ ulong prate;
+
+ switch (clk_id) {
+ case CLK_SPI0:
+ con = readl(&cru->clksel_con[34]);
+ sel = FIELD_GET(CLK_SPI0_SEL_MASK, con);
+ div = FIELD_GET(CLK_SPI0_DIV_MASK, con);
+ break;
+ case CLK_SPI1:
+ con = readl(&cru->clksel_con[34]);
+ sel = FIELD_GET(CLK_SPI1_SEL_MASK, con);
+ div = FIELD_GET(CLK_SPI1_DIV_MASK, con);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ if (sel == CLK_SPI_SEL_24M)
+ prate = OSC_HZ;
+ else if (sel == CLK_SPI_SEL_GPLL_DIV)
+ prate = priv->gpll_div_hz;
+ else if (sel == CLK_SPI_SEL_V0PLL_DIV)
+ prate = priv->v0pll_div_hz;
+ else if (sel == CLK_SPI_SEL_V1PLL_DIV)
+ prate = priv->v1pll_div_hz;
+ else
+ return -EINVAL;
+
+ return DIV_TO_RATE(prate, div);
+}
+
+static ulong rk3506_spi_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
+ ulong rate)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 div, sel;
+
+ if (OSC_HZ % rate == 0) {
+ sel = CLK_SPI_SEL_24M;
+ div = DIV_ROUND_UP(OSC_HZ, rate);
+ } else if (priv->v0pll_div_hz % rate == 0) {
+ sel = CLK_SPI_SEL_V0PLL_DIV;
+ div = DIV_ROUND_UP(priv->v0pll_div_hz, rate);
+ } else if (priv->v1pll_div_hz % rate == 0) {
+ sel = CLK_SPI_SEL_V1PLL_DIV;
+ div = DIV_ROUND_UP(priv->v1pll_div_hz, rate);
+ } else {
+ sel = CLK_SPI_SEL_GPLL_DIV;
+ div = DIV_ROUND_UP(priv->gpll_div_hz, rate);
+ }
+ assert(div - 1 <= 15);
+
+ switch (clk_id) {
+ case CLK_SPI0:
+ rk_clrsetreg(&cru->clksel_con[34],
+ CLK_SPI0_SEL_MASK | CLK_SPI0_DIV_MASK,
+ FIELD_PREP(CLK_SPI0_SEL_MASK, sel) |
+ FIELD_PREP(CLK_SPI0_DIV_MASK, div - 1));
+ break;
+ case CLK_SPI1:
+ rk_clrsetreg(&cru->clksel_con[34],
+ CLK_SPI1_SEL_MASK | CLK_SPI1_DIV_MASK,
+ FIELD_PREP(CLK_SPI1_SEL_MASK, sel) |
+ FIELD_PREP(CLK_SPI1_DIV_MASK, div - 1));
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return rk3506_spi_get_rate(priv, clk_id);
+}
+
+static ulong rk3506_fspi_get_rate(struct rk3506_clk_priv *priv)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 con, div, sel;
+ ulong prate;
+
+ con = readl(&cru->clksel_con[50]);
+ sel = FIELD_GET(SCLK_FSPI_SEL_MASK, con);
+ div = FIELD_GET(SCLK_FSPI_DIV_MASK, con);
+
+ if (sel == SCLK_FSPI_SEL_24M)
+ prate = OSC_HZ;
+ else if (sel == SCLK_FSPI_SEL_GPLL)
+ prate = priv->gpll_hz;
+ else if (sel == SCLK_FSPI_SEL_V0PLL)
+ prate = priv->v0pll_hz;
+ else if (sel == SCLK_FSPI_SEL_V1PLL)
+ prate = priv->v1pll_hz;
+ else
+ return -EINVAL;
+
+ return DIV_TO_RATE(prate, div);
+}
+
+static ulong rk3506_fspi_set_rate(struct rk3506_clk_priv *priv, ulong rate)
+{
+ struct rk3506_cru *cru = priv->cru;
+ int div, sel;
+
+ if (OSC_HZ % rate == 0) {
+ sel = SCLK_FSPI_SEL_24M;
+ div = DIV_ROUND_UP(OSC_HZ, rate);
+ } else if (priv->v0pll_hz % rate == 0) {
+ sel = SCLK_FSPI_SEL_V0PLL;
+ div = DIV_ROUND_UP(priv->v0pll_hz, rate);
+ } else if (priv->v1pll_hz % rate == 0) {
+ sel = SCLK_FSPI_SEL_V1PLL;
+ div = DIV_ROUND_UP(priv->v1pll_hz, rate);
+ } else {
+ sel = SCLK_FSPI_SEL_GPLL;
+ div = DIV_ROUND_UP(priv->gpll_hz, rate);
+ }
+ assert(div - 1 <= 31);
+
+ rk_clrsetreg(&cru->clksel_con[50],
+ SCLK_FSPI_SEL_MASK | SCLK_FSPI_DIV_MASK,
+ FIELD_PREP(SCLK_FSPI_SEL_MASK, sel) |
+ FIELD_PREP(SCLK_FSPI_DIV_MASK, div - 1));
+
+ return rk3506_fspi_get_rate(priv);
+}
+
+static ulong rk3506_vop_dclk_get_rate(struct rk3506_clk_priv *priv)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 con, div, sel;
+ ulong prate;
+
+ con = readl(&cru->clksel_con[60]);
+ sel = FIELD_GET(DCLK_VOP_SEL_MASK, con);
+ div = FIELD_GET(DCLK_VOP_DIV_MASK, con);
+
+ if (sel == DCLK_VOP_SEL_24M)
+ prate = OSC_HZ;
+ else if (sel == DCLK_VOP_SEL_GPLL)
+ prate = priv->gpll_hz;
+ else if (sel == DCLK_VOP_SEL_V0PLL)
+ prate = priv->v0pll_hz;
+ else if (sel == DCLK_VOP_SEL_V1PLL)
+ prate = priv->v1pll_hz;
+ else
+ return -EINVAL;
+
+ return DIV_TO_RATE(prate, div);
+}
+
+static ulong rk3506_vop_dclk_set_rate(struct rk3506_clk_priv *priv, ulong rate)
+{
+ struct rk3506_cru *cru = priv->cru;
+ int div, sel;
+
+ if (OSC_HZ % rate == 0) {
+ sel = DCLK_VOP_SEL_24M;
+ div = DIV_ROUND_UP(OSC_HZ, rate);
+ } else if (priv->v0pll_hz % rate == 0) {
+ sel = DCLK_VOP_SEL_V0PLL;
+ div = DIV_ROUND_UP(priv->v0pll_hz, rate);
+ } else if (priv->v1pll_hz % rate == 0) {
+ sel = DCLK_VOP_SEL_V1PLL;
+ div = DIV_ROUND_UP(priv->v1pll_hz, rate);
+ } else {
+ sel = DCLK_VOP_SEL_GPLL;
+ div = DIV_ROUND_UP(priv->gpll_hz, rate);
+ }
+ assert(div - 1 <= 255);
+
+ rk_clrsetreg(&cru->clksel_con[60],
+ DCLK_VOP_SEL_MASK | DCLK_VOP_DIV_MASK,
+ FIELD_PREP(DCLK_VOP_SEL_MASK, sel) |
+ FIELD_PREP(DCLK_VOP_DIV_MASK, div - 1));
+
+ return rk3506_vop_dclk_get_rate(priv);
+}
+
+static ulong rk3506_mac_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 con, div;
+
+ switch (clk_id) {
+ case CLK_MAC0:
+ case CLK_MAC1:
+ con = readl(&cru->clksel_con[50]);
+ div = FIELD_GET(CLK_MAC_DIV_MASK, con);
+ break;
+ case CLK_MAC_OUT:
+ con = readl(&cru->pmuclksel_con[0]);
+ div = FIELD_GET(CLK_MAC_OUT_DIV_MASK, con);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return DIV_TO_RATE(priv->gpll_hz, div);
+}
+
+static ulong rk3506_mac_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
+ ulong rate)
+{
+ struct rk3506_cru *cru = priv->cru;
+ u32 div;
+
+ switch (clk_id) {
+ case CLK_MAC0:
+ case CLK_MAC1:
+ div = DIV_ROUND_UP(priv->gpll_hz, rate);
+ rk_clrsetreg(&cru->clksel_con[50], CLK_MAC_DIV_MASK,
+ FIELD_PREP(CLK_MAC_DIV_MASK, div - 1));
+ break;
+ case CLK_MAC_OUT:
+ div = DIV_ROUND_UP(priv->gpll_hz, rate);
+ rk_clrsetreg(&cru->pmuclksel_con[0], CLK_MAC_OUT_DIV_MASK,
+ FIELD_PREP(CLK_MAC_OUT_DIV_MASK, div - 1));
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return rk3506_mac_get_rate(priv, clk_id);
+}
+
+static ulong rk3506_clk_get_rate(struct clk *clk)
+{
+ struct rk3506_clk_priv *priv = dev_get_priv(clk->dev);
+ ulong rate = 0;
+
+ if (!priv->gpll_hz || !priv->v0pll_hz || !priv->v1pll_hz) {
+ printf("%s: gpll=%lu, v0pll=%lu, v1pll=%lu\n",
+ __func__, priv->gpll_hz, priv->v0pll_hz, priv->v1pll_hz);
+ return -ENOENT;
+ }
+
+ switch (clk->id) {
+ case PLL_GPLL:
+ rate = priv->gpll_hz;
+ break;
+ case PLL_V0PLL:
+ rate = priv->v0pll_hz;
+ break;
+ case PLL_V1PLL:
+ rate = priv->v1pll_hz;
+ break;
+ case ARMCLK:
+ rate = rk3506_armclk_get_rate(priv);
+ break;
+ case CLK_GPLL_DIV:
+ case CLK_GPLL_DIV_100M:
+ case CLK_V0PLL_DIV:
+ case CLK_V1PLL_DIV:
+ rate = rk3506_pll_div_get_rate(priv, clk->id);
+ break;
+ case ACLK_BUS_ROOT:
+ case HCLK_BUS_ROOT:
+ case PCLK_BUS_ROOT:
+ rate = rk3506_bus_get_rate(priv, clk->id);
+ break;
+ case ACLK_HSPERI_ROOT:
+ case HCLK_LSPERI_ROOT:
+ rate = rk3506_peri_get_rate(priv, clk->id);
+ break;
+ case HCLK_SDMMC:
+ case CCLK_SRC_SDMMC:
+ rate = rk3506_sdmmc_get_rate(priv, clk->id);
+ break;
+ case CLK_SARADC:
+ rate = rk3506_saradc_get_rate(priv, clk->id);
+ break;
+ case CLK_TSADC:
+ case CLK_TSADC_TSEN:
+ rate = rk3506_tsadc_get_rate(priv, clk->id);
+ break;
+ case CLK_I2C0:
+ case CLK_I2C1:
+ case CLK_I2C2:
+ rate = rk3506_i2c_get_rate(priv, clk->id);
+ break;
+ case CLK_PWM0:
+ case CLK_PWM1:
+ rate = rk3506_pwm_get_rate(priv, clk->id);
+ break;
+ case CLK_SPI0:
+ case CLK_SPI1:
+ rate = rk3506_spi_get_rate(priv, clk->id);
+ break;
+ case SCLK_FSPI:
+ rate = rk3506_fspi_get_rate(priv);
+ break;
+ case DCLK_VOP:
+ rate = rk3506_vop_dclk_get_rate(priv);
+ break;
+ case CLK_MAC0:
+ case CLK_MAC1:
+ case CLK_MAC_OUT:
+ rate = rk3506_mac_get_rate(priv, clk->id);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return rate;
+};
+
+static ulong rk3506_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct rk3506_clk_priv *priv = dev_get_priv(clk->dev);
+ ulong ret = 0;
+
+ if (!priv->gpll_hz || !priv->v0pll_hz || !priv->v1pll_hz) {
+ printf("%s: gpll=%lu, v0pll=%lu, v1pll=%lu\n",
+ __func__, priv->gpll_hz, priv->v0pll_hz, priv->v1pll_hz);
+ return -ENOENT;
+ }
+
+ switch (clk->id) {
+ case ARMCLK:
+ if (priv->armclk_hz)
+ rk3506_armclk_set_rate(priv, rate);
+ priv->armclk_hz = rate;
+ break;
+ case CLK_GPLL_DIV:
+ case CLK_GPLL_DIV_100M:
+ case CLK_V0PLL_DIV:
+ case CLK_V1PLL_DIV:
+ ret = rk3506_pll_div_set_rate(priv, clk->id, rate);
+ break;
+ case ACLK_BUS_ROOT:
+ case HCLK_BUS_ROOT:
+ case PCLK_BUS_ROOT:
+ ret = rk3506_bus_set_rate(priv, clk->id, rate);
+ break;
+ case ACLK_HSPERI_ROOT:
+ case HCLK_LSPERI_ROOT:
+ ret = rk3506_peri_set_rate(priv, clk->id, rate);
+ break;
+ case HCLK_SDMMC:
+ case CCLK_SRC_SDMMC:
+ ret = rk3506_sdmmc_set_rate(priv, clk->id, rate);
+ break;
+ case CLK_SARADC:
+ ret = rk3506_saradc_set_rate(priv, clk->id, rate);
+ break;
+ case CLK_TSADC:
+ case CLK_TSADC_TSEN:
+ ret = rk3506_tsadc_set_rate(priv, clk->id, rate);
+ break;
+ case CLK_I2C0:
+ case CLK_I2C1:
+ case CLK_I2C2:
+ ret = rk3506_i2c_set_rate(priv, clk->id, rate);
+ break;
+ case CLK_PWM0:
+ case CLK_PWM1:
+ ret = rk3506_pwm_set_rate(priv, clk->id, rate);
+ break;
+ case CLK_SPI0:
+ case CLK_SPI1:
+ ret = rk3506_spi_set_rate(priv, clk->id, rate);
+ break;
+ case SCLK_FSPI:
+ ret = rk3506_fspi_set_rate(priv, rate);
+ break;
+ case DCLK_VOP:
+ ret = rk3506_vop_dclk_set_rate(priv, rate);
+ break;
+ case CLK_MAC0:
+ case CLK_MAC1:
+ case CLK_MAC_OUT:
+ ret = rk3506_mac_set_rate(priv, clk->id, rate);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return ret;
+};
+
+static struct clk_ops rk3506_clk_ops = {
+ .get_rate = rk3506_clk_get_rate,
+ .set_rate = rk3506_clk_set_rate,
+};
+
+static void rk3506_clk_init(struct rk3506_clk_priv *priv)
+{
+ priv->sync_kernel = false;
+
+ if (!priv->gpll_hz) {
+ priv->gpll_hz = rockchip_pll_get_rate(&rk3506_pll_clks[GPLL],
+ priv->cru, GPLL);
+ priv->gpll_hz = roundup(priv->gpll_hz, 1000);
+ }
+ if (!priv->v0pll_hz) {
+ priv->v0pll_hz = rockchip_pll_get_rate(&rk3506_pll_clks[V0PLL],
+ priv->cru, V0PLL);
+ priv->v0pll_hz = roundup(priv->v0pll_hz, 1000);
+ }
+ if (!priv->v1pll_hz) {
+ priv->v1pll_hz = rockchip_pll_get_rate(&rk3506_pll_clks[V1PLL],
+ priv->cru, V1PLL);
+ priv->v1pll_hz = roundup(priv->v1pll_hz, 1000);
+ }
+ if (!priv->gpll_div_hz) {
+ priv->gpll_div_hz = rk3506_pll_div_get_rate(priv, CLK_GPLL_DIV);
+ priv->gpll_div_hz = roundup(priv->gpll_div_hz, 1000);
+ }
+ if (!priv->gpll_div_100mhz) {
+ priv->gpll_div_100mhz = rk3506_pll_div_get_rate(priv, CLK_GPLL_DIV_100M);
+ priv->gpll_div_100mhz = roundup(priv->gpll_div_100mhz, 1000);
+ }
+ if (!priv->v0pll_div_hz) {
+ priv->v0pll_div_hz = rk3506_pll_div_get_rate(priv, CLK_V0PLL_DIV);
+ priv->v0pll_div_hz = roundup(priv->v0pll_div_hz, 1000);
+ }
+ if (!priv->v1pll_div_hz) {
+ priv->v1pll_div_hz = rk3506_pll_div_get_rate(priv, CLK_V1PLL_DIV);
+ priv->v1pll_div_hz = roundup(priv->v1pll_div_hz, 1000);
+ }
+ if (!priv->armclk_enter_hz) {
+ priv->armclk_enter_hz = rk3506_armclk_get_rate(priv);
+ priv->armclk_init_hz = priv->armclk_enter_hz;
+ }
+}
+
+static int rk3506_clk_probe(struct udevice *dev)
+{
+ struct rk3506_clk_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ rk3506_clk_init(priv);
+
+ /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
+ ret = clk_set_defaults(dev, 1);
+ if (ret)
+ debug("%s clk_set_defaults failed %d\n", __func__, ret);
+ else
+ priv->sync_kernel = true;
+
+ return 0;
+}
+
+static int rk3506_clk_ofdata_to_platdata(struct udevice *dev)
+{
+ struct rk3506_clk_priv *priv = dev_get_priv(dev);
+
+ priv->cru = dev_read_addr_ptr(dev);
+
+ return 0;
+}
+
+static int rk3506_clk_bind(struct udevice *dev)
+{
+ struct udevice *sys_child;
+ struct sysreset_reg *priv;
+ int ret;
+
+#if IS_ENABLED(CONFIG_XPL_BUILD)
+ /* Init pka crypto rate, sel=v0pll, div=3 */
+ rk_clrsetreg(RK3506_SCRU_BASE + 0x0010,
+ CLK_PKA_CRYPTO_SEL_MASK | CLK_PKA_CRYPTO_DIV_MASK,
+ FIELD_PREP(CLK_PKA_CRYPTO_SEL_MASK, CLK_PKA_CRYPTO_SEL_V0PLL) |
+ FIELD_PREP(CLK_PKA_CRYPTO_DIV_MASK, 3));
+
+ /* Change clk core src rate, sel=gpll, div=3 */
+ rk_clrsetreg((ulong)RK3506_CRU_BASE + RK3506_CLKSEL_CON(15),
+ CLK_CORE_SRC_SEL_MASK | CLK_CORE_SRC_DIV_MASK,
+ FIELD_PREP(CLK_CORE_SRC_SEL_MASK, CLK_CORE_SEL_GPLL) |
+ FIELD_PREP(CLK_CORE_SRC_DIV_MASK, 3));
+#endif
+
+ /* The reset driver does not have a device node, so bind it here */
+ ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
+ &sys_child);
+ if (ret) {
+ debug("Warning: No sysreset driver: ret=%d\n", ret);
+ } else {
+ priv = malloc(sizeof(struct sysreset_reg));
+ priv->glb_srst_fst_value = offsetof(struct rk3506_cru,
+ glb_srst_fst);
+ priv->glb_srst_snd_value = offsetof(struct rk3506_cru,
+ glb_srst_snd);
+ dev_set_priv(sys_child, priv);
+ }
+
+#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
+ ret = offsetof(struct rk3506_cru, softrst_con[0]);
+ ret = rk3506_reset_bind_lut(dev, ret, 23);
+ if (ret)
+ debug("Warning: software reset driver bind failed\n");
+#endif
+
+ return 0;
+}
+
+static const struct udevice_id rk3506_clk_ids[] = {
+ { .compatible = "rockchip,rk3506-cru" },
+ { }
+};
+
+U_BOOT_DRIVER(rockchip_rk3506_cru) = {
+ .name = "rockchip_rk3506_cru",
+ .id = UCLASS_CLK,
+ .of_match = rk3506_clk_ids,
+ .priv_auto = sizeof(struct rk3506_clk_priv),
+ .of_to_plat = rk3506_clk_ofdata_to_platdata,
+ .ops = &rk3506_clk_ops,
+ .bind = rk3506_clk_bind,
+ .probe = rk3506_clk_probe,
+};
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index ee5b009d1341..088545c64733 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -16,7 +16,7 @@ obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o
obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
obj-$(CONFIG_RESET_AST2500) += reset-ast2500.o
obj-$(CONFIG_RESET_AST2600) += reset-ast2600.o
-obj-$(CONFIG_RESET_ROCKCHIP) += reset-rockchip.o rst-rk3528.o rst-rk3576.o rst-rk3588.o
+obj-$(CONFIG_RESET_ROCKCHIP) += reset-rockchip.o rst-rk3506.o rst-rk3528.o rst-rk3576.o rst-rk3588.o
obj-$(CONFIG_RESET_MESON) += reset-meson.o
obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
obj-$(CONFIG_RESET_MEDIATEK) += reset-mediatek.o
diff --git a/drivers/reset/rst-rk3506.c b/drivers/reset/rst-rk3506.c
new file mode 100644
index 000000000000..9c384db0589a
--- /dev/null
+++ b/drivers/reset/rst-rk3506.c
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2025 Rockchip Electronics Co., Ltd.
+ * Author: Finley Xiao <finley.xiao@rock-chips.com>
+ */
+
+#include <dm.h>
+#include <asm/arch-rockchip/clock.h>
+#include <dt-bindings/reset/rockchip,rk3506-cru.h>
+
+/* 0xFF9A0000 + 0x0A00 */
+#define RK3506_CRU_RESET_OFFSET(id, reg, bit) [id] = (0 + reg * 16 + bit)
+
+/* mapping table for reset ID to register offset */
+static const int rk3506_register_offset[] = {
+ /* CRU-->SOFTRST_CON00 */
+ RK3506_CRU_RESET_OFFSET(SRST_NCOREPORESET0_AC, 0, 0),
+ RK3506_CRU_RESET_OFFSET(SRST_NCOREPORESET1_AC, 0, 1),
+ RK3506_CRU_RESET_OFFSET(SRST_NCOREPORESET2_AC, 0, 2),
+ RK3506_CRU_RESET_OFFSET(SRST_NCORESET0_AC, 0, 4),
+ RK3506_CRU_RESET_OFFSET(SRST_NCORESET1_AC, 0, 5),
+ RK3506_CRU_RESET_OFFSET(SRST_NCORESET2_AC, 0, 6),
+ RK3506_CRU_RESET_OFFSET(SRST_NL2RESET_AC, 0, 8),
+ RK3506_CRU_RESET_OFFSET(SRST_A_CORE_BIU_AC, 0, 9),
+ RK3506_CRU_RESET_OFFSET(SRST_H_M0_AC, 0, 10),
+
+ /* CRU-->SOFTRST_CON02 */
+ RK3506_CRU_RESET_OFFSET(SRST_NDBGRESET, 2, 10),
+ RK3506_CRU_RESET_OFFSET(SRST_P_CORE_BIU, 2, 14),
+ RK3506_CRU_RESET_OFFSET(SRST_PMU, 2, 15),
+
+ /* CRU-->SOFTRST_CON03 */
+ RK3506_CRU_RESET_OFFSET(SRST_P_DBG, 3, 1),
+ RK3506_CRU_RESET_OFFSET(SRST_POT_DBG, 3, 2),
+ RK3506_CRU_RESET_OFFSET(SRST_P_CORE_GRF, 3, 4),
+ RK3506_CRU_RESET_OFFSET(SRST_CORE_EMA_DETECT, 3, 6),
+ RK3506_CRU_RESET_OFFSET(SRST_REF_PVTPLL_CORE, 3, 7),
+ RK3506_CRU_RESET_OFFSET(SRST_P_GPIO1, 3, 8),
+ RK3506_CRU_RESET_OFFSET(SRST_DB_GPIO1, 3, 9),
+
+ /* CRU-->SOFTRST_CON04 */
+ RK3506_CRU_RESET_OFFSET(SRST_A_CORE_PERI_BIU, 4, 3),
+ RK3506_CRU_RESET_OFFSET(SRST_A_DSMC, 4, 5),
+ RK3506_CRU_RESET_OFFSET(SRST_P_DSMC, 4, 6),
+ RK3506_CRU_RESET_OFFSET(SRST_FLEXBUS, 4, 7),
+ RK3506_CRU_RESET_OFFSET(SRST_A_FLEXBUS, 4, 9),
+ RK3506_CRU_RESET_OFFSET(SRST_H_FLEXBUS, 4, 10),
+ RK3506_CRU_RESET_OFFSET(SRST_A_DSMC_SLV, 4, 11),
+ RK3506_CRU_RESET_OFFSET(SRST_H_DSMC_SLV, 4, 12),
+ RK3506_CRU_RESET_OFFSET(SRST_DSMC_SLV, 4, 13),
+
+ /* CRU-->SOFTRST_CON05 */
+ RK3506_CRU_RESET_OFFSET(SRST_A_BUS_BIU, 5, 3),
+ RK3506_CRU_RESET_OFFSET(SRST_H_BUS_BIU, 5, 4),
+ RK3506_CRU_RESET_OFFSET(SRST_P_BUS_BIU, 5, 5),
+ RK3506_CRU_RESET_OFFSET(SRST_A_SYSRAM, 5, 6),
+ RK3506_CRU_RESET_OFFSET(SRST_H_SYSRAM, 5, 7),
+ RK3506_CRU_RESET_OFFSET(SRST_A_DMAC0, 5, 8),
+ RK3506_CRU_RESET_OFFSET(SRST_A_DMAC1, 5, 9),
+ RK3506_CRU_RESET_OFFSET(SRST_H_M0, 5, 10),
+ RK3506_CRU_RESET_OFFSET(SRST_M0_JTAG, 5, 11),
+ RK3506_CRU_RESET_OFFSET(SRST_H_CRYPTO, 5, 15),
+
+ /* CRU-->SOFTRST_CON06 */
+ RK3506_CRU_RESET_OFFSET(SRST_H_RNG, 6, 0),
+ RK3506_CRU_RESET_OFFSET(SRST_P_BUS_GRF, 6, 1),
+ RK3506_CRU_RESET_OFFSET(SRST_P_TIMER0, 6, 2),
+ RK3506_CRU_RESET_OFFSET(SRST_TIMER0_CH0, 6, 3),
+ RK3506_CRU_RESET_OFFSET(SRST_TIMER0_CH1, 6, 4),
+ RK3506_CRU_RESET_OFFSET(SRST_TIMER0_CH2, 6, 5),
+ RK3506_CRU_RESET_OFFSET(SRST_TIMER0_CH3, 6, 6),
+ RK3506_CRU_RESET_OFFSET(SRST_TIMER0_CH4, 6, 7),
+ RK3506_CRU_RESET_OFFSET(SRST_TIMER0_CH5, 6, 8),
+ RK3506_CRU_RESET_OFFSET(SRST_P_WDT0, 6, 9),
+ RK3506_CRU_RESET_OFFSET(SRST_T_WDT0, 6, 10),
+ RK3506_CRU_RESET_OFFSET(SRST_P_WDT1, 6, 11),
+ RK3506_CRU_RESET_OFFSET(SRST_T_WDT1, 6, 12),
+ RK3506_CRU_RESET_OFFSET(SRST_P_MAILBOX, 6, 13),
+ RK3506_CRU_RESET_OFFSET(SRST_P_INTMUX, 6, 14),
+ RK3506_CRU_RESET_OFFSET(SRST_P_SPINLOCK, 6, 15),
+
+ /* CRU-->SOFTRST_CON07 */
+ RK3506_CRU_RESET_OFFSET(SRST_P_DDRC, 7, 0),
+ RK3506_CRU_RESET_OFFSET(SRST_H_DDRPHY, 7, 1),
+ RK3506_CRU_RESET_OFFSET(SRST_P_DDRMON, 7, 2),
+ RK3506_CRU_RESET_OFFSET(SRST_DDRMON_OSC, 7, 3),
+ RK3506_CRU_RESET_OFFSET(SRST_P_DDR_LPC, 7, 4),
+ RK3506_CRU_RESET_OFFSET(SRST_H_USBOTG0, 7, 5),
+ RK3506_CRU_RESET_OFFSET(SRST_USBOTG0_ADP, 7, 7),
+ RK3506_CRU_RESET_OFFSET(SRST_H_USBOTG1, 7, 8),
+ RK3506_CRU_RESET_OFFSET(SRST_USBOTG1_ADP, 7, 10),
+ RK3506_CRU_RESET_OFFSET(SRST_P_USBPHY, 7, 11),
+ RK3506_CRU_RESET_OFFSET(SRST_USBPHY_POR, 7, 12),
+ RK3506_CRU_RESET_OFFSET(SRST_USBPHY_OTG0, 7, 13),
+ RK3506_CRU_RESET_OFFSET(SRST_USBPHY_OTG1, 7, 14),
+
+ /* CRU-->SOFTRST_CON08 */
+ RK3506_CRU_RESET_OFFSET(SRST_A_DMA2DDR, 8, 0),
+ RK3506_CRU_RESET_OFFSET(SRST_P_DMA2DDR, 8, 1),
+
+ /* CRU-->SOFTRST_CON09 */
+ RK3506_CRU_RESET_OFFSET(SRST_USBOTG0_UTMI, 9, 0),
+ RK3506_CRU_RESET_OFFSET(SRST_USBOTG1_UTMI, 9, 1),
+
+ /* CRU-->SOFTRST_CON10 */
+ RK3506_CRU_RESET_OFFSET(SRST_A_DDRC_0, 10, 0),
+ RK3506_CRU_RESET_OFFSET(SRST_A_DDRC_1, 10, 1),
+ RK3506_CRU_RESET_OFFSET(SRST_A_DDR_BIU, 10, 2),
+ RK3506_CRU_RESET_OFFSET(SRST_DDRC, 10, 3),
+ RK3506_CRU_RESET_OFFSET(SRST_DDRMON, 10, 4),
+
+ /* CRU-->SOFTRST_CON11 */
+ RK3506_CRU_RESET_OFFSET(SRST_H_LSPERI_BIU, 11, 2),
+ RK3506_CRU_RESET_OFFSET(SRST_P_UART0, 11, 4),
+ RK3506_CRU_RESET_OFFSET(SRST_P_UART1, 11, 5),
+ RK3506_CRU_RESET_OFFSET(SRST_P_UART2, 11, 6),
+ RK3506_CRU_RESET_OFFSET(SRST_P_UART3, 11, 7),
+ RK3506_CRU_RESET_OFFSET(SRST_P_UART4, 11, 8),
+ RK3506_CRU_RESET_OFFSET(SRST_UART0, 11, 9),
+ RK3506_CRU_RESET_OFFSET(SRST_UART1, 11, 10),
+ RK3506_CRU_RESET_OFFSET(SRST_UART2, 11, 11),
+ RK3506_CRU_RESET_OFFSET(SRST_UART3, 11, 12),
+ RK3506_CRU_RESET_OFFSET(SRST_UART4, 11, 13),
+ RK3506_CRU_RESET_OFFSET(SRST_P_I2C0, 11, 14),
+ RK3506_CRU_RESET_OFFSET(SRST_I2C0, 11, 15),
+
+ /* CRU-->SOFTRST_CON12 */
+ RK3506_CRU_RESET_OFFSET(SRST_P_I2C1, 12, 0),
+ RK3506_CRU_RESET_OFFSET(SRST_I2C1, 12, 1),
+ RK3506_CRU_RESET_OFFSET(SRST_P_I2C2, 12, 2),
+ RK3506_CRU_RESET_OFFSET(SRST_I2C2, 12, 3),
+ RK3506_CRU_RESET_OFFSET(SRST_P_PWM1, 12, 4),
+ RK3506_CRU_RESET_OFFSET(SRST_PWM1, 12, 5),
+ RK3506_CRU_RESET_OFFSET(SRST_P_SPI0, 12, 10),
+ RK3506_CRU_RESET_OFFSET(SRST_SPI0, 12, 11),
+ RK3506_CRU_RESET_OFFSET(SRST_P_SPI1, 12, 12),
+ RK3506_CRU_RESET_OFFSET(SRST_SPI1, 12, 13),
+ RK3506_CRU_RESET_OFFSET(SRST_P_GPIO2, 12, 14),
+ RK3506_CRU_RESET_OFFSET(SRST_DB_GPIO2, 12, 15),
+
+ /* CRU-->SOFTRST_CON13 */
+ RK3506_CRU_RESET_OFFSET(SRST_P_GPIO3, 13, 0),
+ RK3506_CRU_RESET_OFFSET(SRST_DB_GPIO3, 13, 1),
+ RK3506_CRU_RESET_OFFSET(SRST_P_GPIO4, 13, 2),
+ RK3506_CRU_RESET_OFFSET(SRST_DB_GPIO4, 13, 3),
+ RK3506_CRU_RESET_OFFSET(SRST_H_CAN0, 13, 4),
+ RK3506_CRU_RESET_OFFSET(SRST_CAN0, 13, 5),
+ RK3506_CRU_RESET_OFFSET(SRST_H_CAN1, 13, 6),
+ RK3506_CRU_RESET_OFFSET(SRST_CAN1, 13, 7),
+ RK3506_CRU_RESET_OFFSET(SRST_H_PDM, 13, 8),
+ RK3506_CRU_RESET_OFFSET(SRST_M_PDM, 13, 9),
+ RK3506_CRU_RESET_OFFSET(SRST_PDM, 13, 10),
+ RK3506_CRU_RESET_OFFSET(SRST_SPDIFTX, 13, 11),
+ RK3506_CRU_RESET_OFFSET(SRST_H_SPDIFTX, 13, 12),
+ RK3506_CRU_RESET_OFFSET(SRST_H_SPDIFRX, 13, 13),
+ RK3506_CRU_RESET_OFFSET(SRST_SPDIFRX, 13, 14),
+ RK3506_CRU_RESET_OFFSET(SRST_M_SAI0, 13, 15),
+
+ /* CRU-->SOFTRST_CON14 */
+ RK3506_CRU_RESET_OFFSET(SRST_H_SAI0, 14, 0),
+ RK3506_CRU_RESET_OFFSET(SRST_M_SAI1, 14, 2),
+ RK3506_CRU_RESET_OFFSET(SRST_H_SAI1, 14, 3),
+ RK3506_CRU_RESET_OFFSET(SRST_H_ASRC0, 14, 5),
+ RK3506_CRU_RESET_OFFSET(SRST_ASRC0, 14, 6),
+ RK3506_CRU_RESET_OFFSET(SRST_H_ASRC1, 14, 7),
+ RK3506_CRU_RESET_OFFSET(SRST_ASRC1, 14, 8),
+
+ /* CRU-->SOFTRST_CON17 */
+ RK3506_CRU_RESET_OFFSET(SRST_H_HSPERI_BIU, 17, 4),
+ RK3506_CRU_RESET_OFFSET(SRST_H_SDMMC, 17, 7),
+ RK3506_CRU_RESET_OFFSET(SRST_H_FSPI, 17, 8),
+ RK3506_CRU_RESET_OFFSET(SRST_S_FSPI, 17, 9),
+ RK3506_CRU_RESET_OFFSET(SRST_P_SPI2, 17, 10),
+ RK3506_CRU_RESET_OFFSET(SRST_A_MAC0, 17, 11),
+ RK3506_CRU_RESET_OFFSET(SRST_A_MAC1, 17, 12),
+
+ /* CRU-->SOFTRST_CON18 */
+ RK3506_CRU_RESET_OFFSET(SRST_M_SAI2, 18, 2),
+ RK3506_CRU_RESET_OFFSET(SRST_H_SAI2, 18, 3),
+ RK3506_CRU_RESET_OFFSET(SRST_H_SAI3, 18, 6),
+ RK3506_CRU_RESET_OFFSET(SRST_M_SAI3, 18, 7),
+ RK3506_CRU_RESET_OFFSET(SRST_H_SAI4, 18, 10),
+ RK3506_CRU_RESET_OFFSET(SRST_M_SAI4, 18, 11),
+ RK3506_CRU_RESET_OFFSET(SRST_H_DSM, 18, 12),
+ RK3506_CRU_RESET_OFFSET(SRST_M_DSM, 18, 13),
+ RK3506_CRU_RESET_OFFSET(SRST_P_AUDIO_ADC, 18, 14),
+ RK3506_CRU_RESET_OFFSET(SRST_M_AUDIO_ADC, 18, 15),
+
+ /* CRU-->SOFTRST_CON19 */
+ RK3506_CRU_RESET_OFFSET(SRST_P_SARADC, 19, 0),
+ RK3506_CRU_RESET_OFFSET(SRST_SARADC, 19, 1),
+ RK3506_CRU_RESET_OFFSET(SRST_SARADC_PHY, 19, 2),
+ RK3506_CRU_RESET_OFFSET(SRST_P_OTPC_NS, 19, 3),
+ RK3506_CRU_RESET_OFFSET(SRST_SBPI_OTPC_NS, 19, 4),
+ RK3506_CRU_RESET_OFFSET(SRST_USER_OTPC_NS, 19, 5),
+ RK3506_CRU_RESET_OFFSET(SRST_P_UART5, 19, 6),
+ RK3506_CRU_RESET_OFFSET(SRST_UART5, 19, 7),
+ RK3506_CRU_RESET_OFFSET(SRST_P_GPIO234_IOC, 19, 8),
+
+ /* CRU-->SOFTRST_CON21 */
+ RK3506_CRU_RESET_OFFSET(SRST_A_VIO_BIU, 21, 3),
+ RK3506_CRU_RESET_OFFSET(SRST_H_VIO_BIU, 21, 4),
+ RK3506_CRU_RESET_OFFSET(SRST_H_RGA, 21, 6),
+ RK3506_CRU_RESET_OFFSET(SRST_A_RGA, 21, 7),
+ RK3506_CRU_RESET_OFFSET(SRST_CORE_RGA, 21, 8),
+ RK3506_CRU_RESET_OFFSET(SRST_A_VOP, 21, 9),
+ RK3506_CRU_RESET_OFFSET(SRST_H_VOP, 21, 10),
+ RK3506_CRU_RESET_OFFSET(SRST_VOP, 21, 11),
+ RK3506_CRU_RESET_OFFSET(SRST_P_DPHY, 21, 12),
+ RK3506_CRU_RESET_OFFSET(SRST_P_DSI_HOST, 21, 13),
+ RK3506_CRU_RESET_OFFSET(SRST_P_TSADC, 21, 14),
+ RK3506_CRU_RESET_OFFSET(SRST_TSADC, 21, 15),
+
+ /* CRU-->SOFTRST_CON22 */
+ RK3506_CRU_RESET_OFFSET(SRST_P_GPIO1_IOC, 22, 1),
+};
+
+int rk3506_reset_bind_lut(struct udevice *pdev, u32 reg_offset, u32 reg_number)
+{
+ return rockchip_reset_bind_lut(pdev, rk3506_register_offset,
+ reg_offset, reg_number);
+}
--
2.52.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 05/10] pinctrl: rockchip: Use syscon_regmap_lookup_by_phandle()
2026-01-09 0:49 [PATCH 00/10] rockchip: Add initial support for RK3506 Jonas Karlman
` (3 preceding siblings ...)
2026-01-09 0:49 ` [PATCH 04/10] clk: rockchip: Add support for RK3506 Jonas Karlman
@ 2026-01-09 0:49 ` Jonas Karlman
2026-01-09 0:49 ` [PATCH 06/10] pinctrl: rockchip: Add support for RK3506 Jonas Karlman
` (5 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Jonas Karlman @ 2026-01-09 0:49 UTC (permalink / raw)
To: Kever Yang, Simon Glass, Philipp Tomsich, Tom Rini
Cc: Aaron Griffith, u-boot, Jonas Karlman, Quentin Schulz
Use syscon_regmap_lookup_by_phandle() to simplify the code.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Reviewed-by: Kever Yang <kever.yang@rock-chips.com>
Reviewed-by: Quentin Schulz <quentin.schulz@cherry.de>
---
.../pinctrl/rockchip/pinctrl-rockchip-core.c | 39 ++++++-------------
1 file changed, 12 insertions(+), 27 deletions(-)
diff --git a/drivers/pinctrl/rockchip/pinctrl-rockchip-core.c b/drivers/pinctrl/rockchip/pinctrl-rockchip-core.c
index 4de67aba1c34..273e356e7c02 100644
--- a/drivers/pinctrl/rockchip/pinctrl-rockchip-core.c
+++ b/drivers/pinctrl/rockchip/pinctrl-rockchip-core.c
@@ -10,6 +10,7 @@
#include <syscon.h>
#include <fdtdec.h>
#include <linux/bitops.h>
+#include <linux/err.h>
#include <linux/libfdt.h>
#include "pinctrl-rockchip.h"
@@ -641,37 +642,21 @@ int rockchip_pinctrl_probe(struct udevice *dev)
{
struct rockchip_pinctrl_priv *priv = dev_get_priv(dev);
struct rockchip_pin_ctrl *ctrl;
- struct udevice *syscon;
- struct regmap *regmap;
- int ret = 0;
- /* get rockchip grf syscon phandle */
- ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "rockchip,grf",
- &syscon);
- if (ret) {
- debug("unable to find rockchip,grf syscon device (%d)\n", ret);
- return ret;
+ priv->regmap_base =
+ syscon_regmap_lookup_by_phandle(dev, "rockchip,grf");
+ if (IS_ERR(priv->regmap_base)) {
+ debug("unable to find rockchip,grf regmap\n");
+ return PTR_ERR(priv->regmap_base);
}
- /* get grf-reg base address */
- regmap = syscon_get_regmap(syscon);
- if (!regmap) {
- debug("unable to find rockchip grf regmap\n");
- return -ENODEV;
- }
- priv->regmap_base = regmap;
-
- /* option: get pmu-reg base address */
- ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "rockchip,pmu",
- &syscon);
- if (!ret) {
- /* get pmugrf-reg base address */
- regmap = syscon_get_regmap(syscon);
- if (!regmap) {
- debug("unable to find rockchip pmu regmap\n");
- return -ENODEV;
+ if (dev_read_bool(dev, "rockchip,pmu")) {
+ priv->regmap_pmu =
+ syscon_regmap_lookup_by_phandle(dev, "rockchip,pmu");
+ if (IS_ERR(priv->regmap_pmu)) {
+ debug("unable to find rockchip,pmu regmap\n");
+ return PTR_ERR(priv->regmap_pmu);
}
- priv->regmap_pmu = regmap;
}
ctrl = rockchip_pinctrl_get_soc_data(dev);
--
2.52.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 06/10] pinctrl: rockchip: Add support for RK3506
2026-01-09 0:49 [PATCH 00/10] rockchip: Add initial support for RK3506 Jonas Karlman
` (4 preceding siblings ...)
2026-01-09 0:49 ` [PATCH 05/10] pinctrl: rockchip: Use syscon_regmap_lookup_by_phandle() Jonas Karlman
@ 2026-01-09 0:49 ` Jonas Karlman
2026-01-09 0:49 ` [PATCH 07/10] rockchip: otp: " Jonas Karlman
` (4 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Jonas Karlman @ 2026-01-09 0:49 UTC (permalink / raw)
To: Kever Yang, Simon Glass, Philipp Tomsich, Tom Rini
Cc: Aaron Griffith, u-boot, Jonas Karlman, Ye Zhang
From: Ye Zhang <ye.zhang@rock-chips.com>
Add pinctrl driver for RK3506.
Imported from vendor U-Boot linux-6.1-stan-rkr6 tag with adjustments
to use regmap_update_bits().
Signed-off-by: Ye Zhang <ye.zhang@rock-chips.com>
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/pinctrl/rockchip/Makefile | 1 +
drivers/pinctrl/rockchip/pinctrl-rk3506.c | 462 ++++++++++++++++++
.../pinctrl/rockchip/pinctrl-rockchip-core.c | 9 +
drivers/pinctrl/rockchip/pinctrl-rockchip.h | 1 +
4 files changed, 473 insertions(+)
create mode 100644 drivers/pinctrl/rockchip/pinctrl-rk3506.c
diff --git a/drivers/pinctrl/rockchip/Makefile b/drivers/pinctrl/rockchip/Makefile
index e17415e1ca68..0405df128dfa 100644
--- a/drivers/pinctrl/rockchip/Makefile
+++ b/drivers/pinctrl/rockchip/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_ROCKCHIP_RK3308) += pinctrl-rk3308.o
obj-$(CONFIG_ROCKCHIP_RK3328) += pinctrl-rk3328.o
obj-$(CONFIG_ROCKCHIP_RK3368) += pinctrl-rk3368.o
obj-$(CONFIG_ROCKCHIP_RK3399) += pinctrl-rk3399.o
+obj-$(CONFIG_ROCKCHIP_RK3506) += pinctrl-rk3506.o
obj-$(CONFIG_ROCKCHIP_RK3528) += pinctrl-rk3528.o
obj-$(CONFIG_ROCKCHIP_RK3568) += pinctrl-rk3568.o
obj-$(CONFIG_ROCKCHIP_RK3576) += pinctrl-rk3576.o
diff --git a/drivers/pinctrl/rockchip/pinctrl-rk3506.c b/drivers/pinctrl/rockchip/pinctrl-rk3506.c
new file mode 100644
index 000000000000..969acb66f157
--- /dev/null
+++ b/drivers/pinctrl/rockchip/pinctrl-rk3506.c
@@ -0,0 +1,462 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2024 Rockchip Electronics Co., Ltd.
+ */
+
+#include <dm.h>
+#include <dm/pinctrl.h>
+#include <regmap.h>
+#include <syscon.h>
+
+#include "pinctrl-rockchip.h"
+#include <dt-bindings/pinctrl/rockchip.h>
+
+static int rk3506_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+ int iomux_num = (pin / 8);
+ struct regmap *regmap;
+ int reg, mask;
+ u8 bit;
+ u32 data, rmask;
+
+ if (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
+ regmap = priv->regmap_pmu;
+ else
+ regmap = priv->regmap_base;
+
+ if (bank->bank_num == 1)
+ regmap = priv->regmap_ioc1;
+ else if (bank->bank_num == 4)
+ return 0;
+
+ reg = bank->iomux[iomux_num].offset;
+ if ((pin % 8) >= 4)
+ reg += 0x4;
+ bit = (pin % 4) * 4;
+ mask = 0xf;
+
+ if (bank->recalced_mask & BIT(pin))
+ rockchip_get_recalced_mux(bank, pin, ®, &bit, &mask);
+
+ data = (mask << (bit + 16));
+ rmask = data | (data >> 16);
+ data |= (mux & mask) << bit;
+
+ return regmap_update_bits(regmap, reg, rmask, data);
+}
+
+#define RK3506_DRV_BITS_PER_PIN 8
+#define RK3506_DRV_PINS_PER_REG 2
+#define RK3506_DRV_GPIO0_A_OFFSET 0x100
+#define RK3506_DRV_GPIO0_D_OFFSET 0x830
+#define RK3506_DRV_GPIO1_OFFSET 0x140
+#define RK3506_DRV_GPIO2_OFFSET 0x180
+#define RK3506_DRV_GPIO3_OFFSET 0x1c0
+#define RK3506_DRV_GPIO4_OFFSET 0x840
+
+static int rk3506_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
+ int pin_num, struct regmap **regmap,
+ int *reg, u8 *bit)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+ int ret = 0;
+
+ switch (bank->bank_num) {
+ case 0:
+ *regmap = priv->regmap_pmu;
+ if (pin_num > 24) {
+ ret = -EINVAL;
+ } else if (pin_num < 24) {
+ *reg = RK3506_DRV_GPIO0_A_OFFSET;
+ } else {
+ *reg = RK3506_DRV_GPIO0_D_OFFSET;
+ *bit = 3;
+
+ return 0;
+ }
+ break;
+
+ case 1:
+ *regmap = priv->regmap_ioc1;
+ if (pin_num < 28)
+ *reg = RK3506_DRV_GPIO1_OFFSET;
+ else
+ ret = -EINVAL;
+ break;
+
+ case 2:
+ *regmap = priv->regmap_base;
+ if (pin_num < 17)
+ *reg = RK3506_DRV_GPIO2_OFFSET;
+ else
+ ret = -EINVAL;
+ break;
+
+ case 3:
+ *regmap = priv->regmap_base;
+ if (pin_num < 15)
+ *reg = RK3506_DRV_GPIO3_OFFSET;
+ else
+ ret = -EINVAL;
+ break;
+
+ case 4:
+ *regmap = priv->regmap_base;
+ if (pin_num < 8 || pin_num > 11) {
+ ret = -EINVAL;
+ } else {
+ *reg = RK3506_DRV_GPIO4_OFFSET;
+ *bit = 10;
+
+ return 0;
+ }
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret) {
+ debug("unsupported bank_num %d pin_num %d\n", bank->bank_num, pin_num);
+ return ret;
+ }
+
+ *reg += ((pin_num / RK3506_DRV_PINS_PER_REG) * 4);
+ *bit = pin_num % RK3506_DRV_PINS_PER_REG;
+ *bit *= RK3506_DRV_BITS_PER_PIN;
+
+ return 0;
+}
+
+static int rk3506_set_drive(struct rockchip_pin_bank *bank,
+ int pin_num, int strength)
+{
+ struct regmap *regmap;
+ int reg, ret, i;
+ u32 data, rmask;
+ u8 bit;
+ int rmask_bits = RK3506_DRV_BITS_PER_PIN;
+
+ ret = rk3506_calc_drv_reg_and_bit(bank, pin_num, ®map, ®, &bit);
+ if (ret)
+ return ret;
+
+ for (i = 0, ret = 1; i < strength; i++)
+ ret = (ret << 1) | 1;
+
+ if ((bank->bank_num == 0 && pin_num == 24) || bank->bank_num == 4) {
+ rmask_bits = 2;
+ ret = strength;
+ }
+
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << rmask_bits) - 1) << (bit + 16);
+ rmask = data | (data >> 16);
+ data |= (ret << bit);
+
+ return regmap_update_bits(regmap, reg, rmask, data);
+}
+
+#define RK3506_PULL_BITS_PER_PIN 2
+#define RK3506_PULL_PINS_PER_REG 8
+#define RK3506_PULL_GPIO0_A_OFFSET 0x200
+#define RK3506_PULL_GPIO0_D_OFFSET 0x830
+#define RK3506_PULL_GPIO1_OFFSET 0x210
+#define RK3506_PULL_GPIO2_OFFSET 0x220
+#define RK3506_PULL_GPIO3_OFFSET 0x230
+#define RK3506_PULL_GPIO4_OFFSET 0x840
+
+static int rk3506_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
+ int pin_num, struct regmap **regmap,
+ int *reg, u8 *bit)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+ int ret = 0;
+
+ switch (bank->bank_num) {
+ case 0:
+ *regmap = priv->regmap_pmu;
+ if (pin_num > 24) {
+ ret = -EINVAL;
+ } else if (pin_num < 24) {
+ *reg = RK3506_PULL_GPIO0_A_OFFSET;
+ } else {
+ *reg = RK3506_PULL_GPIO0_D_OFFSET;
+ *bit = 5;
+
+ return 0;
+ }
+ break;
+
+ case 1:
+ *regmap = priv->regmap_ioc1;
+ if (pin_num < 28)
+ *reg = RK3506_PULL_GPIO1_OFFSET;
+ else
+ ret = -EINVAL;
+ break;
+
+ case 2:
+ *regmap = priv->regmap_base;
+ if (pin_num < 17)
+ *reg = RK3506_PULL_GPIO2_OFFSET;
+ else
+ ret = -EINVAL;
+ break;
+
+ case 3:
+ *regmap = priv->regmap_base;
+ if (pin_num < 15)
+ *reg = RK3506_PULL_GPIO3_OFFSET;
+ else
+ ret = -EINVAL;
+ break;
+
+ case 4:
+ *regmap = priv->regmap_base;
+ if (pin_num < 8 || pin_num > 11) {
+ ret = -EINVAL;
+ } else {
+ *reg = RK3506_PULL_GPIO4_OFFSET;
+ *bit = 13;
+
+ return 0;
+ }
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret) {
+ debug("unsupported bank_num %d pin_num %d\n", bank->bank_num, pin_num);
+ return ret;
+ }
+
+ *reg += ((pin_num / RK3506_PULL_PINS_PER_REG) * 4);
+ *bit = pin_num % RK3506_PULL_PINS_PER_REG;
+ *bit *= RK3506_PULL_BITS_PER_PIN;
+
+ return 0;
+}
+
+static int rk3506_set_pull(struct rockchip_pin_bank *bank,
+ int pin_num, int pull)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u8 bit, type;
+ u32 data, rmask;
+
+ if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT)
+ return -EOPNOTSUPP;
+
+ ret = rk3506_calc_pull_reg_and_bit(bank, pin_num, ®map, ®, &bit);
+ if (ret)
+ return ret;
+ type = bank->pull_type[pin_num / 8];
+
+ if ((bank->bank_num == 0 && pin_num == 24) || bank->bank_num == 4)
+ type = 1;
+
+ ret = rockchip_translate_pull_value(type, pull);
+ if (ret < 0) {
+ debug("unsupported pull setting %d\n", pull);
+ return ret;
+ }
+
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << RK3506_PULL_BITS_PER_PIN) - 1) << (bit + 16);
+ rmask = data | (data >> 16);
+ data |= (ret << bit);
+
+ return regmap_update_bits(regmap, reg, rmask, data);
+}
+
+#define RK3506_SMT_BITS_PER_PIN 1
+#define RK3506_SMT_PINS_PER_REG 8
+#define RK3506_SMT_GPIO0_A_OFFSET 0x400
+#define RK3506_SMT_GPIO0_D_OFFSET 0x830
+#define RK3506_SMT_GPIO1_OFFSET 0x410
+#define RK3506_SMT_GPIO2_OFFSET 0x420
+#define RK3506_SMT_GPIO3_OFFSET 0x430
+#define RK3506_SMT_GPIO4_OFFSET 0x840
+
+static int rk3506_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
+ int pin_num,
+ struct regmap **regmap,
+ int *reg, u8 *bit)
+{
+ struct rockchip_pinctrl_priv *priv = bank->priv;
+ int ret = 0;
+
+ switch (bank->bank_num) {
+ case 0:
+ *regmap = priv->regmap_pmu;
+ if (pin_num > 24) {
+ ret = -EINVAL;
+ } else if (pin_num < 24) {
+ *reg = RK3506_SMT_GPIO0_A_OFFSET;
+ } else {
+ *reg = RK3506_SMT_GPIO0_D_OFFSET;
+ *bit = 9;
+
+ return 0;
+ }
+ break;
+
+ case 1:
+ *regmap = priv->regmap_ioc1;
+ if (pin_num < 28)
+ *reg = RK3506_SMT_GPIO1_OFFSET;
+ else
+ ret = -EINVAL;
+ break;
+
+ case 2:
+ *regmap = priv->regmap_base;
+ if (pin_num < 17)
+ *reg = RK3506_SMT_GPIO2_OFFSET;
+ else
+ ret = -EINVAL;
+ break;
+
+ case 3:
+ *regmap = priv->regmap_base;
+ if (pin_num < 15)
+ *reg = RK3506_SMT_GPIO3_OFFSET;
+ else
+ ret = -EINVAL;
+ break;
+
+ case 4:
+ *regmap = priv->regmap_base;
+ if (pin_num < 8 || pin_num > 11) {
+ ret = -EINVAL;
+ } else {
+ *reg = RK3506_SMT_GPIO4_OFFSET;
+ *bit = 8;
+
+ return 0;
+ }
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret) {
+ debug("unsupported bank_num %d pin_num %d\n", bank->bank_num, pin_num);
+ return ret;
+ }
+
+ *reg += ((pin_num / RK3506_SMT_PINS_PER_REG) * 4);
+ *bit = pin_num % RK3506_SMT_PINS_PER_REG;
+ *bit *= RK3506_SMT_BITS_PER_PIN;
+
+ return 0;
+}
+
+static int rk3506_set_schmitt(struct rockchip_pin_bank *bank,
+ int pin_num, int enable)
+{
+ struct regmap *regmap;
+ int reg, ret;
+ u32 data, rmask;
+ u8 bit;
+
+ ret = rk3506_calc_schmitt_reg_and_bit(bank, pin_num, ®map, ®, &bit);
+ if (ret)
+ return ret;
+
+ /* enable the write to the equivalent lower bits */
+ data = ((1 << RK3506_SMT_BITS_PER_PIN) - 1) << (bit + 16);
+ rmask = data | (data >> 16);
+ data |= (enable << bit);
+
+ if ((bank->bank_num == 0 && pin_num == 24) || bank->bank_num == 4) {
+ data = 0x3 << (bit + 16);
+ rmask = data | (data >> 16);
+ data |= ((enable ? 0x3 : 0) << bit);
+ }
+
+ return regmap_update_bits(regmap, reg, rmask, data);
+}
+
+static struct rockchip_mux_recalced_data rk3506_mux_recalced_data[] = {
+ {
+ .num = 0,
+ .pin = 24,
+ .reg = 0x830,
+ .bit = 0,
+ .mask = 0x3
+ },
+};
+
+static struct rockchip_pin_bank rk3506_pin_banks[] = {
+ PIN_BANK_IOMUX_FLAGS_OFFSET(0, 32, "gpio0",
+ IOMUX_WIDTH_4BIT | IOMUX_SOURCE_PMU,
+ IOMUX_WIDTH_4BIT | IOMUX_SOURCE_PMU,
+ IOMUX_WIDTH_4BIT | IOMUX_SOURCE_PMU,
+ IOMUX_8WIDTH_2BIT | IOMUX_SOURCE_PMU,
+ 0x0, 0x8, 0x10, 0x830),
+ PIN_BANK_IOMUX_FLAGS_OFFSET(1, 32, "gpio1",
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ 0x20, 0x28, 0x30, 0x38),
+ PIN_BANK_IOMUX_FLAGS_OFFSET(2, 32, "gpio2",
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ 0x40, 0x48, 0x50, 0x58),
+ PIN_BANK_IOMUX_FLAGS_OFFSET(3, 32, "gpio3",
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ 0x60, 0x68, 0x70, 0x78),
+ PIN_BANK_IOMUX_FLAGS_OFFSET(4, 32, "gpio4",
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ IOMUX_WIDTH_4BIT,
+ 0x80, 0x88, 0x90, 0x98),
+};
+
+static const struct rockchip_pin_ctrl rk3506_pin_ctrl = {
+ .pin_banks = rk3506_pin_banks,
+ .nr_banks = ARRAY_SIZE(rk3506_pin_banks),
+ .iomux_recalced = rk3506_mux_recalced_data,
+ .niomux_recalced = ARRAY_SIZE(rk3506_mux_recalced_data),
+ .set_mux = rk3506_set_mux,
+ .set_pull = rk3506_set_pull,
+ .set_drive = rk3506_set_drive,
+ .set_schmitt = rk3506_set_schmitt,
+};
+
+static const struct udevice_id rk3506_pinctrl_ids[] = {
+ {
+ .compatible = "rockchip,rk3506-pinctrl",
+ .data = (ulong)&rk3506_pin_ctrl
+ },
+ { }
+};
+
+U_BOOT_DRIVER(rockchip_rk3506_pinctrl) = {
+ .name = "rockchip_rk3506_pinctrl",
+ .id = UCLASS_PINCTRL,
+ .of_match = rk3506_pinctrl_ids,
+ .priv_auto = sizeof(struct rockchip_pinctrl_priv),
+ .ops = &rockchip_pinctrl_ops,
+#if CONFIG_IS_ENABLED(OF_REAL)
+ .bind = dm_scan_fdt_dev,
+#endif
+ .probe = rockchip_pinctrl_probe,
+};
diff --git a/drivers/pinctrl/rockchip/pinctrl-rockchip-core.c b/drivers/pinctrl/rockchip/pinctrl-rockchip-core.c
index 273e356e7c02..957dcb520591 100644
--- a/drivers/pinctrl/rockchip/pinctrl-rockchip-core.c
+++ b/drivers/pinctrl/rockchip/pinctrl-rockchip-core.c
@@ -659,6 +659,15 @@ int rockchip_pinctrl_probe(struct udevice *dev)
}
}
+ if (dev_read_bool(dev, "rockchip,ioc1")) {
+ priv->regmap_ioc1 =
+ syscon_regmap_lookup_by_phandle(dev, "rockchip,ioc1");
+ if (IS_ERR(priv->regmap_ioc1)) {
+ debug("unable to find rockchip,ioc1 regmap\n");
+ return PTR_ERR(priv->regmap_ioc1);
+ }
+ }
+
ctrl = rockchip_pinctrl_get_soc_data(dev);
if (!ctrl) {
debug("driver data not available\n");
diff --git a/drivers/pinctrl/rockchip/pinctrl-rockchip.h b/drivers/pinctrl/rockchip/pinctrl-rockchip.h
index ba684baed24d..568e6024b78c 100644
--- a/drivers/pinctrl/rockchip/pinctrl-rockchip.h
+++ b/drivers/pinctrl/rockchip/pinctrl-rockchip.h
@@ -528,6 +528,7 @@ struct rockchip_pinctrl_priv {
struct rockchip_pin_ctrl *ctrl;
struct regmap *regmap_base;
struct regmap *regmap_pmu;
+ struct regmap *regmap_ioc1;
};
extern const struct pinctrl_ops rockchip_pinctrl_ops;
--
2.52.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 07/10] rockchip: otp: Add support for RK3506
2026-01-09 0:49 [PATCH 00/10] rockchip: Add initial support for RK3506 Jonas Karlman
` (5 preceding siblings ...)
2026-01-09 0:49 ` [PATCH 06/10] pinctrl: rockchip: Add support for RK3506 Jonas Karlman
@ 2026-01-09 0:49 ` Jonas Karlman
2026-01-09 0:49 ` [PATCH 08/10] phy: rockchip-inno-usb2: " Jonas Karlman
` (3 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Jonas Karlman @ 2026-01-09 0:49 UTC (permalink / raw)
To: Kever Yang, Simon Glass, Philipp Tomsich, Tom Rini
Cc: Aaron Griffith, u-boot, Jonas Karlman
Add support for the OTP controller in RK3506. The OTPC is similar to the
OTPC in RK3568 and can use the same ops for reading OTP data.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/misc/rockchip-otp.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/misc/rockchip-otp.c b/drivers/misc/rockchip-otp.c
index 46820425a84d..64b6238981b8 100644
--- a/drivers/misc/rockchip-otp.c
+++ b/drivers/misc/rockchip-otp.c
@@ -390,6 +390,10 @@ static const struct udevice_id rockchip_otp_ids[] = {
.compatible = "rockchip,rk3308-otp",
.data = (ulong)&px30_data,
},
+ {
+ .compatible = "rockchip,rk3506-otp",
+ .data = (ulong)&rk3568_data,
+ },
{
.compatible = "rockchip,rk3528-otp",
.data = (ulong)&rk3568_data,
--
2.52.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 08/10] phy: rockchip-inno-usb2: Add support for RK3506
2026-01-09 0:49 [PATCH 00/10] rockchip: Add initial support for RK3506 Jonas Karlman
` (6 preceding siblings ...)
2026-01-09 0:49 ` [PATCH 07/10] rockchip: otp: " Jonas Karlman
@ 2026-01-09 0:49 ` Jonas Karlman
2026-01-09 0:49 ` [PATCH 09/10] net: dwc_eth_qos_rockchip: " Jonas Karlman
` (2 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Jonas Karlman @ 2026-01-09 0:49 UTC (permalink / raw)
To: Kever Yang, Simon Glass, Philipp Tomsich, Tom Rini
Cc: Aaron Griffith, u-boot, Jonas Karlman
Add support for the two USB2.0 PHYs use in the RK3506 SoC.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 20 +++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
index 4ea6600ce7f5..f80b2789333d 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -421,6 +421,22 @@ static const struct rockchip_usb2phy_cfg rk3399_usb2phy_cfgs[] = {
{ /* sentinel */ }
};
+static const struct rockchip_usb2phy_cfg rk3506_phy_cfgs[] = {
+ {
+ .reg = 0xff2b0000,
+ .clkout_ctl_phy = { 0x041c, 7, 2, 0, 0x27 },
+ .port_cfgs = {
+ [USB2PHY_PORT_OTG] = {
+ .phy_sus = { 0x0060, 1, 0, 2, 1 },
+ },
+ [USB2PHY_PORT_HOST] = {
+ .phy_sus = { 0x0070, 1, 0, 2, 1 },
+ }
+ },
+ },
+ { /* sentinel */ }
+};
+
static const struct rockchip_usb2phy_cfg rk3528_phy_cfgs[] = {
{
.reg = 0xffdf0000,
@@ -540,6 +556,10 @@ static const struct udevice_id rockchip_usb2phy_ids[] = {
.compatible = "rockchip,rk3399-usb2phy",
.data = (ulong)&rk3399_usb2phy_cfgs,
},
+ {
+ .compatible = "rockchip,rk3506-usb2phy",
+ .data = (ulong)&rk3506_phy_cfgs,
+ },
{
.compatible = "rockchip,rk3528-usb2phy",
.data = (ulong)&rk3528_phy_cfgs,
--
2.52.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 09/10] net: dwc_eth_qos_rockchip: Add support for RK3506
2026-01-09 0:49 [PATCH 00/10] rockchip: Add initial support for RK3506 Jonas Karlman
` (7 preceding siblings ...)
2026-01-09 0:49 ` [PATCH 08/10] phy: rockchip-inno-usb2: " Jonas Karlman
@ 2026-01-09 0:49 ` Jonas Karlman
2026-01-09 0:49 ` [PATCH 10/10] arch: arm: rockchip: Add initial " Jonas Karlman
2026-01-09 20:23 ` [PATCH 00/10] " Aaron Griffith
10 siblings, 0 replies; 14+ messages in thread
From: Jonas Karlman @ 2026-01-09 0:49 UTC (permalink / raw)
To: Kever Yang, Simon Glass, Philipp Tomsich, Tom Rini,
Joe Hershberger, Ramon Fried, Jerome Forissier
Cc: Aaron Griffith, u-boot, Jonas Karlman
Rockchip RK3506 has two Ethernet controllers based on Synopsys DWC
Ethernet QoS IP.
Add initial support for the RK3506 GMAC variant.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/net/dwc_eth_qos.c | 4 ++
drivers/net/dwc_eth_qos_rockchip.c | 86 ++++++++++++++++++++++++++++++
2 files changed, 90 insertions(+)
diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c
index 551ee0ea6a02..d320646b57f5 100644
--- a/drivers/net/dwc_eth_qos.c
+++ b/drivers/net/dwc_eth_qos.c
@@ -1615,6 +1615,10 @@ static const struct udevice_id eqos_ids[] = {
},
#endif
#if IS_ENABLED(CONFIG_DWC_ETH_QOS_ROCKCHIP)
+ {
+ .compatible = "rockchip,rk3506-gmac",
+ .data = (ulong)&eqos_rockchip_config
+ },
{
.compatible = "rockchip,rk3528-gmac",
.data = (ulong)&eqos_rockchip_config
diff --git a/drivers/net/dwc_eth_qos_rockchip.c b/drivers/net/dwc_eth_qos_rockchip.c
index d646d3ebac87..4ccefda0ef5e 100644
--- a/drivers/net/dwc_eth_qos_rockchip.c
+++ b/drivers/net/dwc_eth_qos_rockchip.c
@@ -50,6 +50,80 @@ struct rockchip_platform_data {
(((tx) ? soc##_GMAC_TXCLK_DLY_ENABLE : soc##_GMAC_TXCLK_DLY_DISABLE) | \
((rx) ? soc##_GMAC_RXCLK_DLY_ENABLE : soc##_GMAC_RXCLK_DLY_DISABLE))
+#define RK3506_GRF_SOC_CON8 0x0020
+#define RK3506_GRF_SOC_CON11 0x002c
+
+#define RK3506_GMAC_RMII_MODE GRF_BIT(1)
+
+#define RK3506_GMAC_CLK_RMII_DIV2 GRF_BIT(3)
+#define RK3506_GMAC_CLK_RMII_DIV20 GRF_CLR_BIT(3)
+
+#define RK3506_GMAC_CLK_SELECT_CRU GRF_CLR_BIT(5)
+#define RK3506_GMAC_CLK_SELECT_IO GRF_BIT(5)
+
+#define RK3506_GMAC_CLK_RMII_GATE GRF_BIT(2)
+#define RK3506_GMAC_CLK_RMII_NOGATE GRF_CLR_BIT(2)
+
+static int rk3506_set_to_rgmii(struct udevice *dev,
+ int tx_delay, int rx_delay)
+{
+ return -EINVAL;
+}
+
+static int rk3506_set_to_rmii(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+ u32 reg;
+
+ reg = data->id == 1 ? RK3506_GRF_SOC_CON11 :
+ RK3506_GRF_SOC_CON8;
+ regmap_write(data->grf, reg, RK3506_GMAC_RMII_MODE);
+
+ return 0;
+}
+
+static int rk3506_set_gmac_speed(struct udevice *dev)
+{
+ struct eqos_priv *eqos = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+ u32 val, reg;
+
+ switch (eqos->phy->speed) {
+ case SPEED_10:
+ val = RK3506_GMAC_CLK_RMII_DIV20;
+ break;
+ case SPEED_100:
+ val = RK3506_GMAC_CLK_RMII_DIV2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ reg = data->id == 1 ? RK3506_GRF_SOC_CON11 :
+ RK3506_GRF_SOC_CON8;
+ regmap_write(data->grf, reg, val);
+
+ return 0;
+}
+
+static void rk3506_set_clock_selection(struct udevice *dev, bool enable)
+{
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+ u32 val, reg;
+
+ val = data->clock_input ? RK3506_GMAC_CLK_SELECT_IO :
+ RK3506_GMAC_CLK_SELECT_CRU;
+ val |= enable ? RK3506_GMAC_CLK_RMII_NOGATE :
+ RK3506_GMAC_CLK_RMII_GATE;
+
+ reg = data->id == 1 ? RK3506_GRF_SOC_CON11 :
+ RK3506_GRF_SOC_CON8;
+ regmap_write(data->grf, reg, val);
+}
+
#define RK3528_VO_GRF_GMAC_CON 0x0018
#define RK3528_VPU_GRF_GMAC_CON5 0x0018
#define RK3528_VPU_GRF_GMAC_CON6 0x001c
@@ -534,6 +608,18 @@ static void rk3588_set_clock_selection(struct udevice *dev, bool enable)
}
static const struct rk_gmac_ops rk_gmac_ops[] = {
+ {
+ .compatible = "rockchip,rk3506-gmac",
+ .set_to_rgmii = rk3506_set_to_rgmii,
+ .set_to_rmii = rk3506_set_to_rmii,
+ .set_gmac_speed = rk3506_set_gmac_speed,
+ .set_clock_selection = rk3506_set_clock_selection,
+ .regs = {
+ 0xff4c8000, /* gmac0 */
+ 0xff4d0000, /* gmac1 */
+ 0x0, /* sentinel */
+ },
+ },
{
.compatible = "rockchip,rk3528-gmac",
.set_to_rgmii = rk3528_set_to_rgmii,
--
2.52.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 10/10] arch: arm: rockchip: Add initial support for RK3506
2026-01-09 0:49 [PATCH 00/10] rockchip: Add initial support for RK3506 Jonas Karlman
` (8 preceding siblings ...)
2026-01-09 0:49 ` [PATCH 09/10] net: dwc_eth_qos_rockchip: " Jonas Karlman
@ 2026-01-09 0:49 ` Jonas Karlman
2026-01-09 9:37 ` Mattijs Korpershoek
2026-01-09 20:23 ` [PATCH 00/10] " Aaron Griffith
10 siblings, 1 reply; 14+ messages in thread
From: Jonas Karlman @ 2026-01-09 0:49 UTC (permalink / raw)
To: Kever Yang, Simon Glass, Philipp Tomsich, Tom Rini,
Lukasz Majewski, Mattijs Korpershoek, Marek Vasut
Cc: Aaron Griffith, u-boot, Jonas Karlman
Rockchip RK3506 is a ARM-based SoC with tri-core Cortex-A7.
Add initial arch support for the RK3506 SoC.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
arch/arm/include/asm/arch-rk3506/boot0.h | 9 ++
arch/arm/include/asm/arch-rk3506/gpio.h | 9 ++
arch/arm/mach-rockchip/Kconfig | 43 ++++++
arch/arm/mach-rockchip/Makefile | 1 +
arch/arm/mach-rockchip/rk3506/Kconfig | 15 ++
arch/arm/mach-rockchip/rk3506/Makefile | 5 +
arch/arm/mach-rockchip/rk3506/clk_rk3506.c | 16 +++
arch/arm/mach-rockchip/rk3506/rk3506.c | 130 ++++++++++++++++++
arch/arm/mach-rockchip/rk3506/syscon_rk3506.c | 19 +++
drivers/usb/gadget/Kconfig | 1 +
include/configs/rk3506_common.h | 38 +++++
11 files changed, 286 insertions(+)
create mode 100644 arch/arm/include/asm/arch-rk3506/boot0.h
create mode 100644 arch/arm/include/asm/arch-rk3506/gpio.h
create mode 100644 arch/arm/mach-rockchip/rk3506/Kconfig
create mode 100644 arch/arm/mach-rockchip/rk3506/Makefile
create mode 100644 arch/arm/mach-rockchip/rk3506/clk_rk3506.c
create mode 100644 arch/arm/mach-rockchip/rk3506/rk3506.c
create mode 100644 arch/arm/mach-rockchip/rk3506/syscon_rk3506.c
create mode 100644 include/configs/rk3506_common.h
diff --git a/arch/arm/include/asm/arch-rk3506/boot0.h b/arch/arm/include/asm/arch-rk3506/boot0.h
new file mode 100644
index 000000000000..8ae46f25a87a
--- /dev/null
+++ b/arch/arm/include/asm/arch-rk3506/boot0.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright Contributors to the U-Boot project. */
+
+#ifndef __ASM_ARCH_BOOT0_H__
+#define __ASM_ARCH_BOOT0_H__
+
+#include <asm/arch-rockchip/boot0.h>
+
+#endif
diff --git a/arch/arm/include/asm/arch-rk3506/gpio.h b/arch/arm/include/asm/arch-rk3506/gpio.h
new file mode 100644
index 000000000000..5516e649b80b
--- /dev/null
+++ b/arch/arm/include/asm/arch-rk3506/gpio.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright Contributors to the U-Boot project. */
+
+#ifndef __ASM_ARCH_GPIO_H__
+#define __ASM_ARCH_GPIO_H__
+
+#include <asm/arch-rockchip/gpio.h>
+
+#endif
diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
index 92bb4aa62f11..7d5372899225 100644
--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -317,6 +317,48 @@ config ROCKCHIP_RK3399
and video codec support. Peripherals include Gigabit Ethernet,
USB2 host and OTG, SDIO, I2S, UARTs, SPI, I2C and PWMs.
+config ROCKCHIP_RK3506
+ bool "Support Rockchip RK3506"
+ select CPU_V7A
+ select SUPPORT_SPL
+ select SPL
+ select CLK
+ select PINCTRL
+ select RAM
+ select REGMAP
+ select SYSCON
+ select BOARD_LATE_INIT
+ select DM_REGULATOR_FIXED
+ select DM_RESET
+ imply BOOTSTD_FULL
+ imply DM_RNG
+ imply ENV_RELOC_GD_ENV_ADDR
+ imply FIT
+ imply LEGACY_IMAGE_FORMAT
+ imply MISC
+ imply MISC_INIT_R
+ imply OF_LIBFDT_OVERLAY
+ imply OF_LIVE
+ imply RNG_ROCKCHIP
+ imply ROCKCHIP_COMMON_BOARD
+ imply ROCKCHIP_COMMON_STACK_ADDR
+ imply ROCKCHIP_EXTERNAL_TPL
+ imply ROCKCHIP_OTP
+ imply SPL_CLK
+ imply SPL_DM_SEQ_ALIAS
+ imply SPL_FIT_SIGNATURE
+ imply SPL_LOAD_FIT
+ imply SPL_OF_CONTROL
+ imply SPL_PINCTRL
+ imply SPL_RAM
+ imply SPL_REGMAP
+ imply SPL_SERIAL
+ imply SPL_SYSCON
+ imply SYS_ARCH_TIMER
+ imply SYSRESET
+ help
+ The Rockchip RK3506 is a ARM-based SoC with a tri-core Cortex-A7.
+
config ROCKCHIP_RK3528
bool "Support Rockchip RK3528"
select ARM64
@@ -745,6 +787,7 @@ source "arch/arm/mach-rockchip/rk3308/Kconfig"
source "arch/arm/mach-rockchip/rk3328/Kconfig"
source "arch/arm/mach-rockchip/rk3368/Kconfig"
source "arch/arm/mach-rockchip/rk3399/Kconfig"
+source "arch/arm/mach-rockchip/rk3506/Kconfig"
source "arch/arm/mach-rockchip/rk3528/Kconfig"
source "arch/arm/mach-rockchip/rk3568/Kconfig"
source "arch/arm/mach-rockchip/rk3576/Kconfig"
diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile
index 06fb527b21a0..d3bc0689f893 100644
--- a/arch/arm/mach-rockchip/Makefile
+++ b/arch/arm/mach-rockchip/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_ROCKCHIP_RK3308) += rk3308/
obj-$(CONFIG_ROCKCHIP_RK3328) += rk3328/
obj-$(CONFIG_ROCKCHIP_RK3368) += rk3368/
obj-$(CONFIG_ROCKCHIP_RK3399) += rk3399/
+obj-$(CONFIG_ROCKCHIP_RK3506) += rk3506/
obj-$(CONFIG_ROCKCHIP_RK3528) += rk3528/
obj-$(CONFIG_ROCKCHIP_RK3568) += rk3568/
obj-$(CONFIG_ROCKCHIP_RK3576) += rk3576/
diff --git a/arch/arm/mach-rockchip/rk3506/Kconfig b/arch/arm/mach-rockchip/rk3506/Kconfig
new file mode 100644
index 000000000000..92f187458c66
--- /dev/null
+++ b/arch/arm/mach-rockchip/rk3506/Kconfig
@@ -0,0 +1,15 @@
+if ROCKCHIP_RK3506
+
+config ROCKCHIP_BOOT_MODE_REG
+ default 0xff910200
+
+config ROCKCHIP_STIMER_BASE
+ default 0xff980000
+
+config SYS_SOC
+ default "rk3506"
+
+config SYS_CONFIG_NAME
+ default "rk3506_common"
+
+endif
diff --git a/arch/arm/mach-rockchip/rk3506/Makefile b/arch/arm/mach-rockchip/rk3506/Makefile
new file mode 100644
index 000000000000..a1760bd0f0a3
--- /dev/null
+++ b/arch/arm/mach-rockchip/rk3506/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+obj-y += rk3506.o
+obj-y += clk_rk3506.o
+obj-y += syscon_rk3506.o
diff --git a/arch/arm/mach-rockchip/rk3506/clk_rk3506.c b/arch/arm/mach-rockchip/rk3506/clk_rk3506.c
new file mode 100644
index 000000000000..ee40e108886c
--- /dev/null
+++ b/arch/arm/mach-rockchip/rk3506/clk_rk3506.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright Contributors to the U-Boot project.
+
+#include <dm.h>
+#include <asm/arch-rockchip/cru_rk3506.h>
+
+int rockchip_get_clk(struct udevice **devp)
+{
+ return uclass_get_device_by_driver(UCLASS_CLK,
+ DM_DRIVER_GET(rockchip_rk3506_cru), devp);
+}
+
+void *rockchip_get_cru(void)
+{
+ return RK3506_CRU_BASE;
+}
diff --git a/arch/arm/mach-rockchip/rk3506/rk3506.c b/arch/arm/mach-rockchip/rk3506/rk3506.c
new file mode 100644
index 000000000000..51b1513d6505
--- /dev/null
+++ b/arch/arm/mach-rockchip/rk3506/rk3506.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright Contributors to the U-Boot project.
+
+#define LOG_CATEGORY LOGC_ARCH
+
+#include <dm.h>
+#include <misc.h>
+#include <asm/arch-rockchip/bootrom.h>
+#include <asm/arch-rockchip/hardware.h>
+
+#define SGRF_BASE 0xff210000
+
+#define FIREWALL_DDR_BASE 0xff5f0000
+#define FW_DDR_MST1_REG 0x24
+
+const char * const boot_devices[BROM_LAST_BOOTSOURCE + 1] = {
+ [BROM_BOOTSOURCE_EMMC] = "/soc/mmc@ff480000",
+ [BROM_BOOTSOURCE_SD] = "/soc/mmc@ff480000",
+};
+
+void board_debug_uart_init(void)
+{
+}
+
+u32 read_brom_bootsource_id(void)
+{
+ u32 bootsource_id = readl(BROM_BOOTSOURCE_ID_ADDR);
+
+ /* Re-map the raw value read from reg to an existing BROM_BOOTSOURCE
+ * enum value to avoid having to create a larger boot_devices table.
+ */
+ if (bootsource_id == 0x81)
+ return BROM_BOOTSOURCE_USB;
+ else if (bootsource_id > BROM_LAST_BOOTSOURCE)
+ log_debug("Unknown bootsource %x\n", bootsource_id);
+
+ return bootsource_id;
+}
+
+int arch_cpu_init(void)
+{
+ u32 val;
+
+ if (!IS_ENABLED(CONFIG_SPL_BUILD))
+ return 0;
+
+ /* Select non-secure OTPC */
+ rk_clrreg(SGRF_BASE + 0x100, BIT(1));
+
+ /* Set the sdmmc/emmc to access ddr memory */
+ val = readl(FIREWALL_DDR_BASE + FW_DDR_MST1_REG);
+ writel(val & 0xffff00ff, FIREWALL_DDR_BASE + FW_DDR_MST1_REG);
+
+ /* Set the fspi to access ddr memory */
+ val = readl(FIREWALL_DDR_BASE + FW_DDR_MST1_REG);
+ writel(val & 0xff00ffff, FIREWALL_DDR_BASE + FW_DDR_MST1_REG);
+
+ /* Set the mac0/mac1 to access ddr memory */
+ val = readl(FIREWALL_DDR_BASE + FW_DDR_MST1_REG);
+ writel(val & 0x00ffffff, FIREWALL_DDR_BASE + FW_DDR_MST1_REG);
+
+ return 0;
+}
+
+#define HP_TIMER_BASE CONFIG_ROCKCHIP_STIMER_BASE
+#define HP_CTRL_REG 0x04
+#define TIMER_EN BIT(0)
+#define HP_LOAD_COUNT0_REG 0x14
+#define HP_LOAD_COUNT1_REG 0x18
+
+void rockchip_stimer_init(void)
+{
+ u32 reg;
+
+ if (!IS_ENABLED(CONFIG_XPL_BUILD))
+ return;
+
+ reg = readl(HP_TIMER_BASE + HP_CTRL_REG);
+ if (reg & TIMER_EN)
+ return;
+
+ asm volatile("mcr p15, 0, %0, c14, c0, 0" : : "r" (CONFIG_COUNTER_FREQUENCY));
+ writel(0xffffffff, HP_TIMER_BASE + HP_LOAD_COUNT0_REG);
+ writel(0xffffffff, HP_TIMER_BASE + HP_LOAD_COUNT1_REG);
+ writel((TIMER_EN << 16) | TIMER_EN, HP_TIMER_BASE + HP_CTRL_REG);
+}
+
+#define RK3506_OTP_CPU_CODE_OFFSET 0x02
+#define RK3506_OTP_SPECIFICATION_OFFSET 0x08
+
+int checkboard(void)
+{
+ u8 cpu_code[2], specification;
+ struct udevice *dev;
+ char suffix[2];
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_ROCKCHIP_OTP) || !CONFIG_IS_ENABLED(MISC))
+ return 0;
+
+ 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 0;
+ }
+
+ /* cpu-code: SoC model, e.g. 0x35 0x06 */
+ ret = misc_read(dev, RK3506_OTP_CPU_CODE_OFFSET, cpu_code, 2);
+ if (ret < 0) {
+ log_debug("Could not read cpu-code, ret=%d\n", ret);
+ return 0;
+ }
+
+ /* specification: SoC variant, e.g. 0xA for RK3506J */
+ ret = misc_read(dev, RK3506_OTP_SPECIFICATION_OFFSET, &specification, 1);
+ if (ret < 0) {
+ log_debug("Could not read specification, ret=%d\n", ret);
+ return 0;
+ }
+ specification &= 0x1f;
+
+ /* for RK3506J i.e. '@' + 0xA = 'J' */
+ suffix[0] = specification > 1 ? '@' + specification : '\0';
+ suffix[1] = '\0';
+
+ printf("SoC: RK%02x%02x%s\n", cpu_code[0], cpu_code[1], suffix);
+
+ return 0;
+}
diff --git a/arch/arm/mach-rockchip/rk3506/syscon_rk3506.c b/arch/arm/mach-rockchip/rk3506/syscon_rk3506.c
new file mode 100644
index 000000000000..2548b0fa2d3a
--- /dev/null
+++ b/arch/arm/mach-rockchip/rk3506/syscon_rk3506.c
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright Contributors to the U-Boot project.
+
+#include <dm.h>
+#include <asm/arch-rockchip/clock.h>
+
+static const struct udevice_id rk3506_syscon_ids[] = {
+ { .compatible = "rockchip,rk3506-grf", .data = ROCKCHIP_SYSCON_GRF },
+ { }
+};
+
+U_BOOT_DRIVER(rockchip_rk3506_syscon) = {
+ .name = "rockchip_rk3506_syscon",
+ .id = UCLASS_SYSCON,
+ .of_match = rk3506_syscon_ids,
+#if CONFIG_IS_ENABLED(OF_REAL)
+ .bind = dm_scan_fdt_dev,
+#endif
+};
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 7e08aeab9043..82a784d2fb00 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -89,6 +89,7 @@ config USB_GADGET_PRODUCT_NUM
default 0x350b if ROCKCHIP_RK3588
default 0x350c if ROCKCHIP_RK3528
default 0x350e if ROCKCHIP_RK3576
+ default 0x350f if ROCKCHIP_RK3506
default 0x4ee0 if ARCH_QCOM
default 0x0
help
diff --git a/include/configs/rk3506_common.h b/include/configs/rk3506_common.h
new file mode 100644
index 000000000000..5e4ef67289f0
--- /dev/null
+++ b/include/configs/rk3506_common.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright Contributors to the U-Boot project. */
+
+#ifndef __CONFIG_RK3506_COMMON_H
+#define __CONFIG_RK3506_COMMON_H
+
+#define CFG_CPUID_OFFSET 0xa
+
+#include "rockchip-common.h"
+
+#define CFG_IRAM_BASE 0xfff80000
+
+#define CFG_SYS_SDRAM_BASE 0
+#define SDRAM_MAX_SIZE 0xc0000000
+
+#ifndef ROCKCHIP_DEVICE_SETTINGS
+#define ROCKCHIP_DEVICE_SETTINGS
+#endif
+
+#define ENV_MEM_LAYOUT_SETTINGS \
+ "scriptaddr=0x00500000\0" \
+ "script_offset_f=0xffe000\0" \
+ "script_size_f=0x2000\0" \
+ "pxefile_addr_r=0x00600000\0" \
+ "kernel_addr_r=0x02080000\0" \
+ "kernel_comp_addr_r=0x08000000\0" \
+ "fdt_addr_r=0x01e00000\0" \
+ "fdtoverlay_addr_r=0x01f00000\0" \
+ "ramdisk_addr_r=0x06000000\0" \
+ "kernel_comp_size=0x2000000\0"
+
+#define CFG_EXTRA_ENV_SETTINGS \
+ "fdtfile=" CONFIG_DEFAULT_FDT_FILE "\0" \
+ ENV_MEM_LAYOUT_SETTINGS \
+ ROCKCHIP_DEVICE_SETTINGS \
+ "boot_targets=" BOOT_TARGETS "\0"
+
+#endif /* __CONFIG_RK3506_COMMON_H */
--
2.52.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 10/10] arch: arm: rockchip: Add initial support for RK3506
2026-01-09 0:49 ` [PATCH 10/10] arch: arm: rockchip: Add initial " Jonas Karlman
@ 2026-01-09 9:37 ` Mattijs Korpershoek
0 siblings, 0 replies; 14+ messages in thread
From: Mattijs Korpershoek @ 2026-01-09 9:37 UTC (permalink / raw)
To: Jonas Karlman, Kever Yang, Simon Glass, Philipp Tomsich, Tom Rini,
Lukasz Majewski, Mattijs Korpershoek, Marek Vasut
Cc: Aaron Griffith, u-boot, Jonas Karlman
Hi Jonas,
Thank you for the patch.
On Fri, Jan 09, 2026 at 00:49, Jonas Karlman <jonas@kwiboo.se> wrote:
> Rockchip RK3506 is a ARM-based SoC with tri-core Cortex-A7.
>
> Add initial arch support for the RK3506 SoC.
>
> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Acked-by: Mattijs Korpershoek <mkorpershoek@kernel.org> # drivers/usb/gadget
> ---
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 00/10] rockchip: Add initial support for RK3506
2026-01-09 0:49 [PATCH 00/10] rockchip: Add initial support for RK3506 Jonas Karlman
` (9 preceding siblings ...)
2026-01-09 0:49 ` [PATCH 10/10] arch: arm: rockchip: Add initial " Jonas Karlman
@ 2026-01-09 20:23 ` Aaron Griffith
2026-01-12 20:16 ` Jonas Karlman
10 siblings, 1 reply; 14+ messages in thread
From: Aaron Griffith @ 2026-01-09 20:23 UTC (permalink / raw)
To: Jonas Karlman; +Cc: Kever Yang, Simon Glass, Philipp Tomsich, Tom Rini, u-boot
Hello Jonas,
On Fri, Jan 09, 2026 at 12:49:41AM +0000, Jonas Karlman wrote:
> This series add initial support for the Rockchip RK3506 SoC.
>
> [..]
#
> With this series, board DTs and defconfigs it should be possible to boot
> into U-Boot proper (without OP-TEE) and still have support for MMC,
> Ethernet, OTP, RNG, LEDs, buttons and USB gadget/host.
I have a Luckfox Lyra Pi W board (with RK3506B) and a Luckfox Lyra
(with RK3506G). I've been using the earlier version of this patchset
for about two weeks to successfully boot Linux on both of these
boards. I'm excited to see this support heading upstream.
Using these patches specifically, I can verify that the RNG and LEDs
work, that it is able to read data from the MMC and USB storage, and
that it successfully loads and runs a Linux kernel.
I was not able to get the Ethernet port to work on my Lyra Pi board,
but that uses your device tree information that is not part of these
patches (and may be incomplete). The specific failure U-boot reports is:
ethernet@ff4d0000 Waiting for PHY auto negotiation to complete.........
TIMEOUT !
So, for what it's worth,
Tested-by: Aaron Griffith <aargri@gmail.com>
Thanks,
-Aaron
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 00/10] rockchip: Add initial support for RK3506
2026-01-09 20:23 ` [PATCH 00/10] " Aaron Griffith
@ 2026-01-12 20:16 ` Jonas Karlman
0 siblings, 0 replies; 14+ messages in thread
From: Jonas Karlman @ 2026-01-12 20:16 UTC (permalink / raw)
To: Aaron Griffith; +Cc: Kever Yang, Simon Glass, Philipp Tomsich, Tom Rini, u-boot
Hi Aaron,
On 1/9/2026 9:23 PM, Aaron Griffith wrote:
> Hello Jonas,
>
> On Fri, Jan 09, 2026 at 12:49:41AM +0000, Jonas Karlman wrote:
>> This series add initial support for the Rockchip RK3506 SoC.
>>
>> [..]
> #
>> With this series, board DTs and defconfigs it should be possible to boot
>> into U-Boot proper (without OP-TEE) and still have support for MMC,
>> Ethernet, OTP, RNG, LEDs, buttons and USB gadget/host.
>
> I have a Luckfox Lyra Pi W board (with RK3506B) and a Luckfox Lyra
> (with RK3506G). I've been using the earlier version of this patchset
> for about two weeks to successfully boot Linux on both of these
> boards. I'm excited to see this support heading upstream.
>
> Using these patches specifically, I can verify that the RNG and LEDs
> work, that it is able to read data from the MMC and USB storage, and
> that it successfully loads and runs a Linux kernel.
>
> I was not able to get the Ethernet port to work on my Lyra Pi board,
> but that uses your device tree information that is not part of these
> patches (and may be incomplete). The specific failure U-boot reports is:
>
> ethernet@ff4d0000 Waiting for PHY auto negotiation to complete.........
> TIMEOUT !
Thanks for testing these patches!
I did some testing on my Luckfox Lyra Pi W (eMMC) board and also found
similar issues that you report.
These issues mostly seem to be related to firewall for USB OTG1 and
MAC1 (ff4d0000) or DT issues related to Ethernet clocks and pinctrl.
The firewall values before we update them in arch_cpu_init():
=> md.l ff5f0020 5
ff5f0020: ffffffff ffffffff ffffffff ffffff00 ................
ff5f0030: ffffffff ....
The following firewall values seem to help fix MAC0/1 and USB OTG1:
=> md.l ff5f0020 5
ff5f0020: ffffffff f00000ff fffffff0 fff0ff00 ................
ff5f0030: ffffffff ....
We could possible set all these to 0 to allow all masters to access
memory, will send a v2 that configures the firewall like above.
Adding something like following to the ethernet-phy nodes seem to solve
the Ethernet issues in U-Boot on my Lyra Pi:
assigned-clocks = <&cru CLK_MAC_OUT>;
assigned-clock-rates = <50000000>;
clocks = <&cru CLK_MAC_OUT>;
pinctrl-names = "default";
pinctrl-0 = <ð_clk0_25m_out>;
or
pinctrl-0 = <ð_clk1_25m_out>;
Vendor DT for Lyra Pi seem to set CLK_MAC_OUT to 25 MHz, but this does
not seem to work in U-Boot and I can not see anything wrong in the clk
driver, so maybe it is meant to be set to 50 MHz.
Will update my rk3506 branch to include these changes and later also
send out a v2 of this series including the firewall fix.
Regards,
Jonas
>
> So, for what it's worth,
>
> Tested-by: Aaron Griffith <aargri@gmail.com>
>
> Thanks,
> -Aaron
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-01-12 20:16 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-09 0:49 [PATCH 00/10] rockchip: Add initial support for RK3506 Jonas Karlman
2026-01-09 0:49 ` [PATCH 01/10] rockchip: mkimage: Add " Jonas Karlman
2026-01-09 0:49 ` [PATCH 02/10] ram: rockchip: Add basic " Jonas Karlman
2026-01-09 0:49 ` [PATCH 03/10] dt-bindings: clock: rockchip: Add RK3506 clock and reset unit Jonas Karlman
2026-01-09 0:49 ` [PATCH 04/10] clk: rockchip: Add support for RK3506 Jonas Karlman
2026-01-09 0:49 ` [PATCH 05/10] pinctrl: rockchip: Use syscon_regmap_lookup_by_phandle() Jonas Karlman
2026-01-09 0:49 ` [PATCH 06/10] pinctrl: rockchip: Add support for RK3506 Jonas Karlman
2026-01-09 0:49 ` [PATCH 07/10] rockchip: otp: " Jonas Karlman
2026-01-09 0:49 ` [PATCH 08/10] phy: rockchip-inno-usb2: " Jonas Karlman
2026-01-09 0:49 ` [PATCH 09/10] net: dwc_eth_qos_rockchip: " Jonas Karlman
2026-01-09 0:49 ` [PATCH 10/10] arch: arm: rockchip: Add initial " Jonas Karlman
2026-01-09 9:37 ` Mattijs Korpershoek
2026-01-09 20:23 ` [PATCH 00/10] " Aaron Griffith
2026-01-12 20:16 ` Jonas Karlman
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox