Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH net v2] ipvs: fix NULL deref in ip_vs_add_service error path
From: Simon Horman @ 2026-04-03 15:09 UTC (permalink / raw)
  To: Weiming Shi
  Cc: Julian Anastasov, Pablo Neira Ayuso, Florian Westphal,
	David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Phil Sutter, netdev, lvs-devel, netfilter-devel, coreteam,
	Xiang Mei
In-Reply-To: <20260401075800.3344266-2-bestswngs@gmail.com>

On Wed, Apr 01, 2026 at 03:58:01PM +0800, Weiming Shi wrote:
> When ip_vs_bind_scheduler() succeeds in ip_vs_add_service(), the local
> variable sched is set to NULL.  If ip_vs_start_estimator() subsequently
> fails, the out_err cleanup calls ip_vs_unbind_scheduler(svc, sched)
> with sched == NULL.  ip_vs_unbind_scheduler() passes the cur_sched NULL
> check (because svc->scheduler was set by the successful bind) but then
> dereferences the NULL sched parameter at sched->done_service, causing a
> kernel panic at offset 0x30 from NULL.
> 
>  Oops: general protection fault, probably for non-canonical address 0xdffffc0000000006: 0000 [#1] PREEMPT SMP KASAN NOPTI
>  KASAN: null-ptr-deref in range [0x0000000000000030-0x0000000000000037]
>  RIP: 0010:ip_vs_unbind_scheduler (net/netfilter/ipvs/ip_vs_sched.c:69)
>  Call Trace:
>   <TASK>
>   ip_vs_add_service.isra.0 (net/netfilter/ipvs/ip_vs_ctl.c:1500)
>   do_ip_vs_set_ctl (net/netfilter/ipvs/ip_vs_ctl.c:2809)
>   nf_setsockopt (net/netfilter/nf_sockopt.c:102)
>   ip_setsockopt (net/ipv4/ip_sockglue.c:1427)
>   raw_setsockopt (net/ipv4/raw.c:850)
>   do_sock_setsockopt (net/socket.c:2322)
>   __sys_setsockopt (net/socket.c:2339)
>   __x64_sys_setsockopt (net/socket.c:2350)
>   do_syscall_64 (arch/x86/entry/syscall_64.c:94)
>   entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130)
>   </TASK>
> 
> Fix by simply not clearing the local sched variable after a successful
> bind.  ip_vs_unbind_scheduler() already detects whether a scheduler is
> installed via svc->scheduler, and keeping sched non-NULL ensures the
> error path passes the correct pointer to both ip_vs_unbind_scheduler()
> and ip_vs_scheduler_put().
> 
> Fixes: 05f00505a89a ("ipvs: fix crash if scheduler is changed")
> Reported-by: Xiang Mei <xmei5@asu.edu>
> Signed-off-by: Weiming Shi <bestswngs@gmail.com>

Acked-by: Simon Horman <horms@kernel.org>


^ permalink raw reply

* [PATCH net-next v3 5/5] selftests: net: bridge: add tests for MRC and QQIC validation
From: Ujjal Roy @ 2026-04-03 15:00 UTC (permalink / raw)
  To: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Nikolay Aleksandrov, Ido Schimmel, David Ahern,
	Shuah Khan, Andy Roulin, Yong Wang, Petr Machata
  Cc: Ujjal Roy, bridge, netdev, linux-kernel, linux-kselftest
In-Reply-To: <20260403150050.1235-1-royujjal@gmail.com>

Update bridge selftests that configure Max Resp Time (MRT) and Querier
Query Interval (QQI) parameters and validate the resulting Query packet
fields for Max Resp Code (MRC) and Querier Query Interval Code (QQIC).

These tests cover the IGMPv3 and MLDv2 for below cases:
* MRC and QQIC in linear range.
* MRC and QQIC in non-linear range.

TEST: Vlan multicast snooping enable                                [ OK ]
TEST: Vlan mcast_query_interval global option default value         [ OK ]
Vlan 10 mcast_query_interval (QQIC) test cases:
TEST: Number of tagged IGMPv2 general query                         [ OK ]
TEST: IGMPv3 QQIC linear value 60                                   [ OK ]
TEST: MLDv2 QQIC linear value 60                                    [ OK ]
TEST: IGMPv3 QQIC non linear value 160                              [ OK ]
TEST: MLDv2 QQIC non linear value 160                               [ OK ]
TEST: Vlan mcast_query_response_interval global option default value   [ OK ]
Vlan 10 mcast_query_response_interval (MRC) test cases:
TEST: IGMPv3 MRC linear value 60                                    [ OK ]
TEST: IGMPv3 MRC non linear value 160                               [ OK ]
TEST: MLDv2 MRC linear value 30000                                  [ OK ]
TEST: MLDv2 MRC non linear value 60000                              [ OK ]

Signed-off-by: Ujjal Roy <royujjal@gmail.com>
---
 .../selftests/net/forwarding/.gitignore       |   2 +
 .../testing/selftests/net/forwarding/Makefile |  10 ++
 .../net/forwarding/bridge_vlan_mcast.sh       | 157 +++++++++++++++++-
 .../selftests/net/forwarding/mc_decode.c      |  73 ++++++++
 .../selftests/net/forwarding/mc_encode.c      |  78 +++++++++
 5 files changed, 315 insertions(+), 5 deletions(-)
 create mode 100644 tools/testing/selftests/net/forwarding/mc_decode.c
 create mode 100644 tools/testing/selftests/net/forwarding/mc_encode.c

diff --git a/tools/testing/selftests/net/forwarding/.gitignore b/tools/testing/selftests/net/forwarding/.gitignore
index 418ff96c52ef..aa0c7f1afb4b 100644
--- a/tools/testing/selftests/net/forwarding/.gitignore
+++ b/tools/testing/selftests/net/forwarding/.gitignore
@@ -1,3 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
 forwarding.config
 ipmr
+mc_encode
+mc_decode
diff --git a/tools/testing/selftests/net/forwarding/Makefile b/tools/testing/selftests/net/forwarding/Makefile
index bbaf4d937dd8..a26da846632d 100644
--- a/tools/testing/selftests/net/forwarding/Makefile
+++ b/tools/testing/selftests/net/forwarding/Makefile
@@ -1,5 +1,15 @@
 # SPDX-License-Identifier: GPL-2.0+ OR MIT
 
+top_srcdir = ../../../../..
+
+CFLAGS += -Wall -Wl,--no-as-needed -O2 -g -I$(top_srcdir)/usr/include $(KHDR_INCLUDES)
+CFLAGS += -I$(top_srcdir)/tools/include
+
+TEST_GEN_FILES := \
+	mc_encode \
+	mc_decode \
+# end of TEST_GEN_FILES
+
 TEST_PROGS := \
 	bridge_activity_notify.sh \
 	bridge_fdb_learning_limit.sh \
diff --git a/tools/testing/selftests/net/forwarding/bridge_vlan_mcast.sh b/tools/testing/selftests/net/forwarding/bridge_vlan_mcast.sh
index 72dfbeaf56b9..89598712f869 100755
--- a/tools/testing/selftests/net/forwarding/bridge_vlan_mcast.sh
+++ b/tools/testing/selftests/net/forwarding/bridge_vlan_mcast.sh
@@ -5,6 +5,7 @@ ALL_TESTS="vlmc_control_test vlmc_querier_test vlmc_igmp_mld_version_test \
 	   vlmc_last_member_test vlmc_startup_query_test vlmc_membership_test \
 	   vlmc_querier_intvl_test vlmc_query_intvl_test vlmc_query_response_intvl_test \
 	   vlmc_router_port_test vlmc_filtering_test"
+TEST_NAME=""
 NUM_NETIFS=4
 CHECK_TC="yes"
 TEST_GROUP="239.10.10.10"
@@ -96,6 +97,17 @@ cleanup()
 	vrf_cleanup
 }
 
+check_binary()
+{
+	local cmd=$1; shift
+	local args=$@
+
+	if [[ ! -x "$(command -v "$cmd")" ]]; then
+		log_test_skip "$args $cmd not found"
+		return $EXIT_STATUS
+	fi
+}
+
 vlmc_v2join_test()
 {
 	local expect=$1
@@ -162,14 +174,27 @@ vlmc_query_cnt_setup()
 {
 	local type=$1
 	local dev=$2
+	local intvl_match="$3"
 
 	if [[ $type == "igmp" ]]; then
+		# This matches: IP Protocol 2 (IGMP)
 		tc filter add dev $dev egress pref 10 prot 802.1Q \
 			flower vlan_id 10 vlan_ethtype ipv4 dst_ip 224.0.0.1 ip_proto 2 \
+			action continue
+		# AND Type 0x11 (Query) at offset 24 after IP
+		# IP (20 byte IP + 4 bytes Option)
+		tc filter add dev $dev egress pref 20 prot 802.1Q u32 \
+			match u8 0x11 0xff at 24 $intvl_match \
 			action pass
 	else
+		# This matches: ICMPv6
 		tc filter add dev $dev egress pref 10 prot 802.1Q \
 			flower vlan_id 10 vlan_ethtype ipv6 dst_ip ff02::1 ip_proto icmpv6 \
+			action continue
+		# AND Type 0x82 (Query) at offset 48 after IPv6
+		# IPv6 (40 bytes IPv6 + 2 bytes next HDR + 4 bytes Option + 2 byte pad)
+		tc filter add dev $dev egress pref 20 prot 802.1Q u32 \
+			match u8 0x82 0xff at 48 $intvl_match \
 			action pass
 	fi
 
@@ -181,9 +206,46 @@ vlmc_query_cnt_cleanup()
 	local dev=$1
 
 	ip link set dev br0 type bridge mcast_stats_enabled 0
+	tc filter del dev $dev egress pref 20
 	tc filter del dev $dev egress pref 10
 }
 
+vlmc_query_get_intvl_match()
+{
+	local type=$1
+	local version=$2
+	local interval=$3
+	local encode=""
+
+	if [ "$interval" = "" ]; then
+		return
+	fi
+
+	if [ "$TEST_NAME" = "vlmc_query_intvl_test" ]; then
+		# QQIC is 8-bit floating point encoding for IGMPv3 and MLDv2
+		encode="$(./mc_encode 8 $interval)"
+		if [ "${type}v${version}" = "igmpv3" ]; then
+			# IP 20 bytes + 4 bytes Option + IGMPv3[9]
+			echo "match u8 $encode 0xff at 33"
+		elif [ "${type}v${version}" = "mldv2" ]; then
+			# IPv6 40 + 2 next HDR + 4 Option + 2 pad + MLDv2[25]
+			echo "match u8 $encode 0xff at 73"
+		fi
+	elif [ "$TEST_NAME" = "vlmc_query_response_intvl_test" ]; then
+		if [ "${type}v${version}" = "igmpv3" ]; then
+			# MRC is 8-bit floating point encoding for MLDv2
+			encode="$(./mc_encode 8 $interval)"
+			# IP 20 bytes + 4 bytes Option + IGMPv3[1]
+			echo "match u8 $encode 0xff at 25"
+		elif [ "${type}v${version}" = "mldv2" ]; then
+			# MRC is 16-bit floating point encoding for MLDv2
+			encode="$(./mc_encode 16 $interval)"
+			# IPv6 40 + 2 next HDR + 4 Option + 2 pad + MLDv2[4]
+			echo "match u16 $encode 0xffff at 52"
+		fi
+	fi
+}
+
 vlmc_check_query()
 {
 	local type=$1
@@ -191,9 +253,12 @@ vlmc_check_query()
 	local dev=$3
 	local expect=$4
 	local time=$5
+	local interval=$6
+	local intvl_match=""
 	local ret=0
 
-	vlmc_query_cnt_setup $type $dev
+	intvl_match="$(vlmc_query_get_intvl_match $type $version $interval)"
+	vlmc_query_cnt_setup $type $dev "$intvl_match"
 
 	local pre_tx_xstats=$(vlmc_query_cnt_xstats $type $version $dev)
 	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_querier 1
@@ -201,7 +266,7 @@ vlmc_check_query()
 	if [[ $ret -eq 0 ]]; then
 		sleep $time
 
-		local tcstats=$(tc_rule_stats_get $dev 10 egress)
+		local tcstats=$(tc_rule_stats_get $dev 20 egress)
 		local post_tx_xstats=$(vlmc_query_cnt_xstats $type $version $dev)
 
 		if [[ $tcstats != $expect || \
@@ -428,6 +493,10 @@ vlmc_querier_intvl_test()
 
 vlmc_query_intvl_test()
 {
+	TEST_NAME="vlmc_query_intvl_test"
+
+	check_binary "./mc_encode" "$TEST_NAME: verify" || return 1
+
 	RET=0
 	local goutput=`bridge -j vlan global show`
 	echo -n $goutput |
@@ -440,6 +509,7 @@ vlmc_query_intvl_test()
 	check_err $? "Wrong default mcast_query_interval global vlan option value"
 	log_test "Vlan mcast_query_interval global option default value"
 
+	echo "Vlan 10 mcast_query_interval (QQIC) test cases:"
 	RET=0
 	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_startup_query_count 0
 	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_query_interval 200
@@ -447,14 +517,52 @@ vlmc_query_intvl_test()
 	# 1 is sent immediately, then 2 more in the next 5 seconds
 	vlmc_check_query igmp 2 $swp1 3 5
 	check_err $? "Wrong number of tagged IGMPv2 general queries sent"
-	log_test "Vlan 10 mcast_query_interval option changed to 200"
+	log_test "Number of tagged IGMPv2 general query"
+
+	RET=0
+	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_igmp_version 3
+	check_err $? "Could not set mcast_igmp_version in vlan 10"
+	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_mld_version 2
+	check_err $? "Could not set mcast_mld_version in vlan 10"
+
+	RET=0
+	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_query_interval 6000
+	check_err $? "Could not set mcast_query_interval in vlan 10"
+	# 1 is sent immediately, IGMPv3 QQIC should match with linear value 60s
+	vlmc_check_query igmp 3 $swp1 1 1 60
+	check_err $? "Wrong QQIC in sent tagged IGMPv3 general queries"
+	log_test "IGMPv3 QQIC linear value 60"
+	RET=0
+	# 1 is sent immediately, MLDv2 QQIC should match with linear value 60s
+	vlmc_check_query mld 2 $swp1 1 1 60
+	check_err $? "Wrong QQIC in sent tagged MLDv2 general queries"
+	log_test "MLDv2 QQIC linear value 60"
 
+	RET=0
+	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_query_interval 16000
+	check_err $? "Could not set mcast_query_interval in vlan 10"
+	# 1 is sent immediately, IGMPv3 QQIC should match with non linear value 160s
+	vlmc_check_query igmp 3 $swp1 1 1 160
+	check_err $? "Wrong QQIC in sent tagged IGMPv3 general queries"
+	log_test "IGMPv3 QQIC non linear value 160"
+	RET=0
+	# 1 is sent immediately, MLDv2 QQIC should match with non linear value 160s
+	vlmc_check_query mld 2 $swp1 1 1 160
+	check_err $? "Wrong QQIC in sent tagged MLDv2 general queries"
+	log_test "MLDv2 QQIC non linear value 160"
+
+	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_igmp_version 2
+	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_mld_version 1
 	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_startup_query_count 2
 	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_query_interval 12500
 }
 
 vlmc_query_response_intvl_test()
 {
+	TEST_NAME="vlmc_query_response_intvl_test"
+
+	check_binary "./mc_encode" "$TEST_NAME: verify" || return 1
+
 	RET=0
 	local goutput=`bridge -j vlan global show`
 	echo -n $goutput |
@@ -468,10 +576,49 @@ vlmc_query_response_intvl_test()
 	log_test "Vlan mcast_query_response_interval global option default value"
 
 	RET=0
-	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_query_response_interval 200
+	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_startup_query_count 0
+	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_igmp_version 3
+	check_err $? "Could not set mcast_igmp_version in vlan 10"
+
+	echo "Vlan 10 mcast_query_response_interval (MRC) test cases:"
+	RET=0
+	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_query_response_interval 600
+	check_err $? "Could not set mcast_query_response_interval in vlan 10"
+	# 1 is sent immediately, IGMPv3 MRC should match with linear value 60 units of 1/10s
+	vlmc_check_query igmp 3 $swp1 1 1 60
+	check_err $? "Wrong MRC in sent tagged IGMPv3 general queries"
+	log_test "IGMPv3 MRC linear value 60"
+
+	RET=0
+	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_query_response_interval 1600
+	check_err $? "Could not set mcast_query_response_interval in vlan 10"
+	# 1 is sent immediately, IGMPv3 MRC should match with non linear value 160 unit of 1/10s
+	vlmc_check_query igmp 3 $swp1 1 1 160
+	check_err $? "Wrong MRC in sent tagged IGMPv3 general queries"
+	log_test "IGMPv3 MRC non linear value 160"
+
+	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_mld_version 2
+	check_err $? "Could not set mcast_mld_version in vlan 10"
+
+	RET=0
+	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_query_response_interval 3000
+	check_err $? "Could not set mcast_query_response_interval in vlan 10"
+	# 1 is sent immediately, MLDv2 MRC should match with linear value 30000(ms)
+	vlmc_check_query mld 2 $swp1 1 1 30000
+	check_err $? "Wrong MRC in sent tagged MLDv2 general queries"
+	log_test "MLDv2 MRC linear value 30000"
+
+	RET=0
+	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_query_response_interval 6000
 	check_err $? "Could not set mcast_query_response_interval in vlan 10"
-	log_test "Vlan 10 mcast_query_response_interval option changed to 200"
+	# 1 is sent immediately, MLDv2 MRC should match with non linear value 60000(ms)
+	vlmc_check_query mld 2 $swp1 1 1 60000
+	check_err $? "Wrong MRC in sent tagged MLDv2 general queries"
+	log_test "MLDv2 MRC non linear value 60000"
 
+	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_igmp_version 2
+	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_mld_version 1
+	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_startup_query_count 2
 	bridge vlan global set vid 10 dev br0 mcast_snooping 1 mcast_query_response_interval 1000
 }
 
diff --git a/tools/testing/selftests/net/forwarding/mc_decode.c b/tools/testing/selftests/net/forwarding/mc_decode.c
new file mode 100644
index 000000000000..2c5e784226e4
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/mc_decode.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+#include <stdlib.h>
+#include <linux/bitops.h>
+
+/* 8-bit floating-point exponential field decode */
+#define FP_8BIT_EXP(value)		(((value) >> 4) & 0x07)
+#define FP_8BIT_MAN(value)		((value) & 0x0f)
+
+/* 16-bit floating-point exponential field decode */
+#define FP_16BIT_EXP(value)		(((value) >> 12) & 0x0007)
+#define FP_16BIT_MAN(value)		((value) & 0x0fff)
+
+/* 8-bit floating-point exponential field linear threshold */
+#define FP_8BIT_MIN_THRESHOLD		128
+/* 8-bit non linear max representable (mant = 0xF, exp = 7) -> 31744 */
+#define FP_8BIT_MAX_THRESHOLD		31744
+
+/* 16-bit floating-point exponential field linear threshold */
+#define FP_16BIT_MIN_THRESHOLD		32768UL
+/* 16-bit non linear max representable (mant = 0xFFF, exp = 7) -> 8387584 */
+#define FP_16BIT_MAX_THRESHOLD		8387584
+
+/* This decodes 8-bit floating-point exponential values */
+static inline uint32_t decode_8bit_field(const u8 code)
+{
+	if (code < FP_8BIT_MIN_THRESHOLD) {
+		return code;
+	} else {
+		uint32_t mc_man, mc_exp;
+
+		mc_exp = FP_8BIT_EXP(code);
+		mc_man = FP_8BIT_MAN(code);
+		return (mc_man | 0x10) << (mc_exp + 3);
+	}
+}
+
+/* This decodes 16-bit floating-point exponential values */
+static inline uint32_t decode_16bit_field(const uint16_t code)
+{
+	if (code < FP_16BIT_MIN_THRESHOLD) {
+		return code;
+	} else {
+		uint32_t mc_man, mc_exp;
+
+		mc_exp = FP_16BIT_EXP(code);
+		mc_man = FP_16BIT_MAN(code);
+
+		return (mc_man | 0x1000) << (mc_exp + 3);
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	uint32_t bits = 8, code = 0, decode = 0;
+
+	if (argc != 3)
+		return 1;
+
+	if (bits != 8 && bits != 16)
+		return 1;
+
+	bits = atoi(argv[1]);
+	code = atoi(argv[2]);
+
+	if (bits == 8)
+		decode = decode_8bit_field(code);
+	else
+		decode = decode_16bit_field(code);
+	printf("%u\n", decode);
+
+	return 0;
+}
diff --git a/tools/testing/selftests/net/forwarding/mc_encode.c b/tools/testing/selftests/net/forwarding/mc_encode.c
new file mode 100644
index 000000000000..24d9bd9299cc
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/mc_encode.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+#include <stdlib.h>
+#include <linux/bitops.h>
+
+/* 8-bit floating-point exponential field linear threshold */
+#define FP_8BIT_MIN_THRESHOLD		128
+/* 8-bit non linear max representable (mant = 0xF, exp = 7) -> 31744 */
+#define FP_8BIT_MAX_THRESHOLD		31744
+
+/* 16-bit floating-point exponential field linear threshold */
+#define FP_16BIT_MIN_THRESHOLD		32768UL
+/* 16-bit non linear max representable (mant = 0xFFF, exp = 7) -> 8387584 */
+#define FP_16BIT_MAX_THRESHOLD		8387584
+
+/* This encodes value to 8-bit floating-point exponential format */
+static inline uint8_t encode_8bit_field(unsigned int value)
+{
+	uint8_t mc_exp, mc_man;
+
+	/* Value < 128 is literal */
+	if (value < FP_8BIT_MIN_THRESHOLD)
+		return value;
+
+	/* Saturate at max representable (mant = 0xF, exp = 7) -> 31744 */
+	if (value >= FP_8BIT_MAX_THRESHOLD)
+		return 0xFF;
+
+	mc_exp  = fls(value) - 8;
+	mc_man = (value >> (mc_exp + 3)) & 0x0F;
+
+	return 0x80 | (mc_exp << 4) | mc_man;
+}
+
+/* This encodes value to 16-bit floating-point exponential format */
+static inline uint16_t encode_16bit_field(unsigned int value)
+{
+	uint16_t mc_man, mc_exp;
+
+	/* Value < 32768 is literal */
+	if (value < FP_16BIT_MIN_THRESHOLD)
+		return value;
+
+	/* Saturate at max representable (mant = 0xFFF, exp = 7) -> 8387584 */
+	if (value >= FP_16BIT_MAX_THRESHOLD)
+		return 0xFFFF;
+
+	mc_exp = fls(value) - 16;
+	mc_man = (value >> (mc_exp + 3)) & 0x0FFF;
+
+	return 0x8000 | (mc_exp << 12) | mc_man;
+}
+
+int main(int argc, char *argv[])
+{
+	unsigned int bits = 8, value = 0;
+	uint8_t encoded8 = 0;
+	uint16_t encoded16 = 0;
+
+	if (argc != 3)
+		return 1;
+
+	bits = atoi(argv[1]);
+	value = atoi(argv[2]);
+
+	if (bits != 8 && bits != 16)
+		return 1;
+
+	if (bits == 8) {
+		encoded8 = encode_8bit_field(value);
+		printf("%hhu\n", encoded8);
+	} else {
+		encoded16 = encode_16bit_field(value);
+		printf("%hu\n", encoded16);
+	}
+
+	return 0;
+}
-- 
2.43.0


^ permalink raw reply related

* [PATCH net-next v3 4/5] ipv6: mld: encode multicast exponential fields
From: Ujjal Roy @ 2026-04-03 15:00 UTC (permalink / raw)
  To: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Nikolay Aleksandrov, Ido Schimmel, David Ahern,
	Shuah Khan, Andy Roulin, Yong Wang, Petr Machata
  Cc: Ujjal Roy, bridge, netdev, linux-kernel, linux-kselftest
In-Reply-To: <20260403150050.1235-1-royujjal@gmail.com>

In MLD, QQIC and MRC fields are not correctly encoded when
generating query packets. Since the receiver of the query
interprets these fields using the MLDv2 floating-point
decoding logic, any value that exceeds the linear threshold
is incorrectly parsed as an exponential value, leading to
an incorrect interval calculation.

Encode and assign the corresponding protocol fields during
query generation. Introduce the logic to dynamically
calculate the exponent and mantissa using bit-scan (fls).
This ensures QQIC (8-bit) and MRC (16-bit) fields are
properly encoded when transmitting query packets with
intervals that exceed their respective linear thresholds
(128 for QQI; 32768 for MRD).

RFC3810: If QQIC >= 128, the QQIC field represents a
floating-point value as follows:
     0 1 2 3 4 5 6 7
    +-+-+-+-+-+-+-+-+
    |1| exp | mant  |
    +-+-+-+-+-+-+-+-+

RFC3810: If Maximum Response Code >= 32768, the Maximum
Response Code field represents a floating-point value as
follows:
     0 1 2 3 4 5 6 7 8 9 A B C D E F
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |1| exp |          mant         |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Signed-off-by: Ujjal Roy <royujjal@gmail.com>
---
 include/net/mld.h         | 122 ++++++++++++++++++++++++++++++++++++++
 net/bridge/br_multicast.c |   4 +-
 2 files changed, 124 insertions(+), 2 deletions(-)

diff --git a/include/net/mld.h b/include/net/mld.h
index da3299545ebd..147e8c44eb28 100644
--- a/include/net/mld.h
+++ b/include/net/mld.h
@@ -90,12 +90,134 @@ struct mld2_query {
 #define MLDV2_QQIC_MAN(value)	((value) & 0x0f)
 
 #define MLD_QQIC_MIN_THRESHOLD	128
+/* Max representable (mant = 0xF, exp = 7) -> 31744 */
+#define MLD_QQIC_MAX_THRESHOLD	31744
 #define MLD_MRC_MIN_THRESHOLD	32768UL
+/* Max representable (mant = 0xFFF, exp = 7) -> 8387584 */
+#define MLD_MRC_MAX_THRESHOLD	8387584
 #define MLDV1_MRD_MAX_COMPAT	(MLD_MRC_MIN_THRESHOLD - 1)
 
 #define MLD_MAX_QUEUE		8
 #define MLD_MAX_SKBS		32
 
+/* V2 exponential field encoding */
+
+/*
+ * Calculate Maximum Response Code from Maximum Response Delay
+ *
+ * MRC represents the 16-bit encoded form of Maximum Response
+ * Delay (MRD); once decoded, the resulting value is in
+ * milliseconds.
+ *
+ * RFC3810 defines only the decoding formula:
+ * Maximum Response Delay = (mant | 0x1000) << (exp + 3)
+ *
+ * but does NOT define the encoding procedure. To derive exponent:
+ *
+ * For the 16-bit MRC, the "hidden bit" (0x1000) is left shifted by 12
+ * to sit above the 12-bit mantissa. The RFC then shifts this entire
+ * block left by (exp + 3) to reconstruct the value.
+ * So, 'hidden bit' is the MSB which is shifted by (12 + exp + 3).
+ *
+ * Total left shift of the hidden bit = 12 + (exp + 3) = exp + 15.
+ * This is the MSB at the 0-based bit position: (exp + 15).
+ * Since fls() is 1-based, fls(value) - 1 = exp + 15.
+ *
+ * Therefore:
+ *     exp  = fls(value) - 16
+ *     mant = (value >> (exp + 3)) & 0x0FFF
+ *
+ * Final encoding formula:
+ *     0x8000 | (exp << 12) | mant
+ *
+ * Example (value = 1311744):
+ *  0               1               2               3
+ *  0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0| 1311744
+ * |                      ^-^--------mant---------^ ^...(exp+3)...^| exp=5
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Encoded:
+ *   0x8000 | (5 << 12) | 0x404 = 0xD404
+ */
+static inline u16 mldv2_mrc(unsigned long mrd)
+{
+	u16 mc_man, mc_exp;
+
+	/* RFC3810: MRC < 32768 is literal */
+	if (mrd < MLD_MRC_MIN_THRESHOLD)
+		return mrd;
+
+	/* Saturate at max representable (mant = 0xFFF, exp = 7) -> 8387584 */
+	if (mrd >= MLD_MRC_MAX_THRESHOLD)
+		return 0xFFFF;
+
+	mc_exp = fls(mrd) - 16;
+	mc_man = (mrd >> (mc_exp + 3)) & 0x0FFF;
+
+	return 0x8000 | (mc_exp << 12) | mc_man;
+}
+
+/*
+ * Calculate Querier's Query Interval Code from Query Interval
+ *
+ * QQIC represents the 8-bit encoded form of Query Interval (QQI);
+ * once decoded, the resulting value is in seconds.
+ *
+ * MLDv2 QQIC 8-bit floating-point encoding (RFC3810).
+ *
+ * RFC3810 defines only the decoding formula:
+ * QQI = (mant | 0x10) << (exp + 3)
+ *
+ * but does NOT define the encoding procedure. To derive exponent:
+ *
+ * For any value of mantissa and exponent, the decoding formula
+ * indicates that the "hidden bit" (0x10) is shifted 4 bits left
+ * to sit above the 4-bit mantissa. The RFC again shifts this
+ * entire block left by (exp + 3) to reconstruct the value.
+ * So, 'hidden bit' is the MSB which is shifted by (4 + exp + 3).
+ *
+ * Total left shift of the 'hidden bit' = 4 + (exp + 3) = exp + 7.
+ * This is the MSB at the 0-based bit position: (exp + 7).
+ * Since fls() is 1-based, fls(value) - 1 = exp + 7.
+ *
+ * Therefore:
+ *     exp  = fls(value) - 8
+ *     mant = (value >> (exp + 3)) & 0x0F
+ *
+ * Final encoding formula:
+ *     0x80 | (exp << 4) | mant
+ *
+ * Example (value = 3200):
+ *  0               1
+ *  0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 0| (value = 3200)
+ * |        ^-^-mant^ ^..(exp+3)..^| exp = 4, mant = 9
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Encoded:
+ *   0x80 | (4 << 4) | 9 = 0xC9
+ */
+static inline u8 mldv2_qqic(unsigned long value)
+{
+	u8 mc_man, mc_exp;
+
+	/* RFC3810: QQIC < 128 is literal */
+	if (value < MLD_QQIC_MIN_THRESHOLD)
+		return value;
+
+	/* Saturate at max representable (mant = 0xF, exp = 7) -> 31744 */
+	if (value >= MLD_QQIC_MAX_THRESHOLD)
+		return 0xFF;
+
+	mc_exp  = fls(value) - 8;
+	mc_man = (value >> (mc_exp + 3)) & 0x0F;
+
+	return 0x80 | (mc_exp << 4) | mc_man;
+}
+
 /* V2 exponential field decoding */
 
 /* Calculate Maximum Response Delay from Maximum Response Code
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 27010744d7ae..a22e44c4fa48 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1181,7 +1181,7 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge_mcast *brm
 		break;
 	case 2:
 		mld2q = (struct mld2_query *)icmp6_hdr(skb);
-		mld2q->mld2q_mrc = htons((u16)jiffies_to_msecs(interval));
+		mld2q->mld2q_mrc = htons((u16)mldv2_mrc(jiffies_to_msecs(interval)));
 		mld2q->mld2q_type = ICMPV6_MGM_QUERY;
 		mld2q->mld2q_code = 0;
 		mld2q->mld2q_cksum = 0;
@@ -1190,7 +1190,7 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge_mcast *brm
 		mld2q->mld2q_suppress = sflag;
 		mld2q->mld2q_qrv = 2;
 		mld2q->mld2q_nsrcs = htons(llqt_srcs);
-		mld2q->mld2q_qqic = brmctx->multicast_query_interval / HZ;
+		mld2q->mld2q_qqic = mldv2_qqic(brmctx->multicast_query_interval / HZ);
 		mld2q->mld2q_mca = *group;
 		csum = &mld2q->mld2q_cksum;
 		csum_start = (void *)mld2q;
-- 
2.43.0


^ permalink raw reply related

* [PATCH net-next v3 3/5] ipv4: igmp: encode multicast exponential fields
From: Ujjal Roy @ 2026-04-03 15:00 UTC (permalink / raw)
  To: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Nikolay Aleksandrov, Ido Schimmel, David Ahern,
	Shuah Khan, Andy Roulin, Yong Wang, Petr Machata
  Cc: Ujjal Roy, bridge, netdev, linux-kernel, linux-kselftest
In-Reply-To: <20260403150050.1235-1-royujjal@gmail.com>

In IGMP, QQIC and MRC fields are not correctly encoded
when generating query packets. Since the receiver of the
query interprets these fields using the IGMPv3 floating-
point decoding logic, any value that exceeds the linear
threshold is incorrectly parsed as an exponential value,
leading to an incorrect interval calculation.

Encode and assign the corresponding protocol fields during
query generation. Introduce the logic to dynamically
calculate the exponent and mantissa using bit-scan (fls).
This ensures QQIC and MRC fields (8-bit) are properly
encoded when transmitting query packets with intervals
that exceed their respective linear threshold value of
128 (for QQI/MRT).

RFC 3376: if QQIC/MRC >= 128, the QQIC/MRC field represents
a floating-point value as follows:
     0 1 2 3 4 5 6 7
    +-+-+-+-+-+-+-+-+
    |1| exp | mant  |
    +-+-+-+-+-+-+-+-+

Signed-off-by: Ujjal Roy <royujjal@gmail.com>
---
 include/linux/igmp.h      | 87 +++++++++++++++++++++++++++++++++++++++
 net/bridge/br_multicast.c | 14 +++----
 2 files changed, 93 insertions(+), 8 deletions(-)

diff --git a/include/linux/igmp.h b/include/linux/igmp.h
index 0624410e75c6..4e895829cd0e 100644
--- a/include/linux/igmp.h
+++ b/include/linux/igmp.h
@@ -109,6 +109,93 @@ struct ip_mc_list {
 
 /* IGMPV3 floating-point exponential field threshold */
 #define IGMPV3_EXP_MIN_THRESHOLD	128
+/* Max representable (mant = 0xF, exp = 7) -> 31744 */
+#define IGMPV3_EXP_MAX_THRESHOLD	31744
+
+/* V3 exponential field encoding */
+
+/* IGMPv3 QQIC/MRC 8-bit exponential field encode.
+ *
+ * RFC3376 defines only the decoding formula:
+ * QQI/MRT = (mant | 0x10) << (exp + 3)
+ *
+ * but does NOT define the encoding procedure. To derive exponent:
+ *
+ * For any value of mantissa and exponent, the decoding formula
+ * indicates that the "hidden bit" (0x10) is shifted 4 bits left
+ * to sit above the 4-bit mantissa. The RFC again shifts this
+ * entire block left by (exp + 3) to reconstruct the value.
+ * So, 'hidden bit' is the MSB which is shifted by (4 + exp + 3).
+ *
+ * Total left shift of the 'hidden bit' = 4 + (exp + 3) = exp + 7.
+ * This is the MSB at the 0-based bit position: (exp + 7).
+ * Since fls() is 1-based, fls(value) - 1 = exp + 7.
+ *
+ * Therefore:
+ *     exp  = fls(value) - 8
+ *     mant = (value >> (exp + 3)) & 0x0F
+ *
+ * Final encoding formula:
+ *     0x80 | (exp << 4) | mant
+ *
+ * Example (value = 3200):
+ *  0               1
+ *  0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 0| (value = 3200)
+ * |        ^-^-mant^ ^..(exp+3)..^| exp = 4, mant = 9
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Encoded:
+ *   0x80 | (4 << 4) | 9 = 0xC9
+ */
+static inline u8 igmpv3_exp_field_encode(unsigned long value)
+{
+	u8 mc_exp, mc_man;
+
+	/* RFC3376: QQIC/MRC < 128 is literal */
+	if (value < IGMPV3_EXP_MIN_THRESHOLD)
+		return value;
+
+	/* Saturate at max representable (mant = 0xF, exp = 7) -> 31744 */
+	if (value >= IGMPV3_EXP_MAX_THRESHOLD)
+		return 0xFF;
+
+	mc_exp  = fls(value) - 8;
+	mc_man = (value >> (mc_exp + 3)) & 0x0F;
+
+	return 0x80 | (mc_exp << 4) | mc_man;
+}
+
+/* Calculate Maximum Response Code from Max Resp Time
+ *
+ * MRC represents the encoded form of Max Resp Time (MRT); once
+ * decoded, the resulting value is in units of 0.1 seconds (100 ms).
+ */
+static inline u8 igmpv3_mrc(unsigned long mrt)
+{
+	/* RFC3376, relevant sections:
+	 *  - 4.1.1. Maximum Response Code
+	 *  - 8.3. Query Response Interval
+	 */
+	return igmpv3_exp_field_encode(mrt);
+}
+
+/* Calculate Querier's Query Interval Code from Query Interval
+ *
+ * QQIC represents the encoded form of Query Interval (QI); once
+ * decoded, the resulting value is in units of seconds.
+ */
+static inline u8 igmpv3_qqic(unsigned long qi)
+{
+	/* RFC3376, relevant sections:
+	 *  - 4.1.7. QQIC (Querier's Query Interval Code)
+	 *  - 8.2. Query Interval
+	 *  - 8.12. Older Version Querier Present Timeout
+	 *    (the [Query Interval] in the last Query received)
+	 */
+	return igmpv3_exp_field_encode(qi);
+}
 
 /* V3 exponential field decoding */
 
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 1438c023db62..27010744d7ae 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -934,12 +934,12 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge_mcast *brm
 	size_t pkt_size, igmp_hdr_size;
 	unsigned long now = jiffies;
 	struct igmpv3_query *ihv3;
+	unsigned long lmqt, mrt;
 	void *csum_start = NULL;
 	__sum16 *csum = NULL;
 	struct sk_buff *skb;
 	struct igmphdr *ih;
 	struct ethhdr *eth;
-	unsigned long lmqt;
 	struct iphdr *iph;
 	u16 lmqt_srcs = 0;
 
@@ -1004,15 +1004,15 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge_mcast *brm
 	skb_put(skb, 24);
 
 	skb_set_transport_header(skb, skb->len);
+	mrt = group ? brmctx->multicast_last_member_interval :
+		      brmctx->multicast_query_response_interval;
 	*igmp_type = IGMP_HOST_MEMBERSHIP_QUERY;
 
 	switch (brmctx->multicast_igmp_version) {
 	case 2:
 		ih = igmp_hdr(skb);
 		ih->type = IGMP_HOST_MEMBERSHIP_QUERY;
-		ih->code = (group ? brmctx->multicast_last_member_interval :
-				    brmctx->multicast_query_response_interval) /
-			   (HZ / IGMP_TIMER_SCALE);
+		ih->code = mrt / (HZ / IGMP_TIMER_SCALE);
 		ih->group = group;
 		ih->csum = 0;
 		csum = &ih->csum;
@@ -1021,11 +1021,9 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge_mcast *brm
 	case 3:
 		ihv3 = igmpv3_query_hdr(skb);
 		ihv3->type = IGMP_HOST_MEMBERSHIP_QUERY;
-		ihv3->code = (group ? brmctx->multicast_last_member_interval :
-				      brmctx->multicast_query_response_interval) /
-			     (HZ / IGMP_TIMER_SCALE);
+		ihv3->code = igmpv3_mrc(mrt / (HZ / IGMP_TIMER_SCALE));
 		ihv3->group = group;
-		ihv3->qqic = brmctx->multicast_query_interval / HZ;
+		ihv3->qqic = igmpv3_qqic(brmctx->multicast_query_interval / HZ);
 		ihv3->nsrcs = htons(lmqt_srcs);
 		ihv3->resv = 0;
 		ihv3->suppress = sflag;
-- 
2.43.0


^ permalink raw reply related

* [PATCH net-next v3 2/5] ipv6: mld: rename mldv2_mrc() and add mldv2_qqi()
From: Ujjal Roy @ 2026-04-03 15:00 UTC (permalink / raw)
  To: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Nikolay Aleksandrov, Ido Schimmel, David Ahern,
	Shuah Khan, Andy Roulin, Yong Wang, Petr Machata
  Cc: Ujjal Roy, bridge, netdev, linux-kernel, linux-kselftest
In-Reply-To: <20260403150050.1235-1-royujjal@gmail.com>

Rename mldv2_mrc() to mldv2_mrd() as it is used to calculate
the Maximum Response Delay from the Maximum Response Code.

Introduce a new API mldv2_qqi() to define the existing
calculation logic of QQI from QQIC. This also organizes
the existing mld_update_qi() API.

Signed-off-by: Ujjal Roy <royujjal@gmail.com>
---
 include/net/mld.h         | 70 +++++++++++++++++++++++++++++++++------
 net/bridge/br_multicast.c |  2 +-
 net/ipv6/mcast.c          | 19 ++---------
 3 files changed, 64 insertions(+), 27 deletions(-)

diff --git a/include/net/mld.h b/include/net/mld.h
index c07359808493..da3299545ebd 100644
--- a/include/net/mld.h
+++ b/include/net/mld.h
@@ -89,29 +89,79 @@ struct mld2_query {
 #define MLDV2_QQIC_EXP(value)	(((value) >> 4) & 0x07)
 #define MLDV2_QQIC_MAN(value)	((value) & 0x0f)
 
-#define MLD_EXP_MIN_LIMIT	32768UL
-#define MLDV1_MRD_MAX_COMPAT	(MLD_EXP_MIN_LIMIT - 1)
+#define MLD_QQIC_MIN_THRESHOLD	128
+#define MLD_MRC_MIN_THRESHOLD	32768UL
+#define MLDV1_MRD_MAX_COMPAT	(MLD_MRC_MIN_THRESHOLD - 1)
 
 #define MLD_MAX_QUEUE		8
 #define MLD_MAX_SKBS		32
 
-static inline unsigned long mldv2_mrc(const struct mld2_query *mlh2)
-{
-	/* RFC3810, 5.1.3. Maximum Response Code */
-	unsigned long ret, mc_mrc = ntohs(mlh2->mld2q_mrc);
+/* V2 exponential field decoding */
 
-	if (mc_mrc < MLD_EXP_MIN_LIMIT) {
-		ret = mc_mrc;
+/* Calculate Maximum Response Delay from Maximum Response Code
+ *
+ * After decode, MRC represents the Maximum Response Delay (MRD) in units
+ * of milliseconds.
+ *
+ * RFC3810, 5.1.3. defines the decoding formula:
+ *      0 1 2 3 4 5 6 7 8 9 A B C D E F
+ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *     |1| exp |          mant         |
+ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * Maximum Response Delay = (mant | 0x1000) << (exp+3)
+ */
+static inline unsigned long mldv2_mrd(const struct mld2_query *mlh2)
+{
+	/* RFC3810, relevant sections:
+	 *  - 5.1.3. Maximum Response Code
+	 *  - 9.3. Query Response Interval
+	 */
+	unsigned long mc_mrc = ntohs(mlh2->mld2q_mrc);
+
+	if (mc_mrc < MLD_MRC_MIN_THRESHOLD) {
+		return mc_mrc;
 	} else {
 		unsigned long mc_man, mc_exp;
 
 		mc_exp = MLDV2_MRC_EXP(mc_mrc);
 		mc_man = MLDV2_MRC_MAN(mc_mrc);
 
-		ret = (mc_man | 0x1000) << (mc_exp + 3);
+		return (mc_man | 0x1000) << (mc_exp + 3);
 	}
+}
 
-	return ret;
+/* Calculate Querier's Query Interval from Querier's Query Interval Code
+ *
+ * After decode, QQIC represents the Querier's Query Interval in units
+ * of seconds.
+ *
+ * RFC3810, 5.1.9. defines the decoding formula:
+ *      0 1 2 3 4 5 6 7
+ *     +-+-+-+-+-+-+-+-+
+ *     |1| exp | mant  |
+ *     +-+-+-+-+-+-+-+-+
+ * QQI = (mant | 0x10) << (exp + 3)
+ */
+static inline unsigned long mldv2_qqi(const struct mld2_query *mlh2)
+{
+	/* RFC3810, relevant sections:
+	 *  - 5.1.9. QQIC (Querier's Query Interval Code)
+	 *  - 9.2. Query Interval
+	 *  - 9.12. Older Version Querier Present Timeout
+	 *    (the [Query Interval] in the last Query received)
+	 */
+	unsigned long qqic = mlh2->mld2q_qqic;
+
+	if (qqic < MLD_QQIC_MIN_THRESHOLD) {
+		return qqic;
+	} else {
+		unsigned long mc_man, mc_exp;
+
+		mc_exp = MLDV2_QQIC_EXP(qqic);
+		mc_man = MLDV2_QQIC_MAN(qqic);
+
+		return (mc_man | 0x10) << (mc_exp + 3);
+	}
 }
 
 #endif
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 9fec76e887bc..1438c023db62 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -3606,7 +3606,7 @@ static int br_ip6_multicast_query(struct net_bridge_mcast *brmctx,
 		    mld2q->mld2q_suppress)
 			goto out;
 
-		max_delay = max(msecs_to_jiffies(mldv2_mrc(mld2q)), 1UL);
+		max_delay = max(msecs_to_jiffies(mldv2_mrd(mld2q)), 1UL);
 	}
 
 	is_general_query = group && ipv6_addr_any(group);
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 3330adcf26db..6ddc18ac59b9 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -1315,20 +1315,7 @@ static void mld_update_qi(struct inet6_dev *idev,
 	 *  - 9.12. Older Version Querier Present Timeout
 	 *    (the [Query Interval] in the last Query received)
 	 */
-	unsigned long mc_qqi;
-
-	if (mlh2->mld2q_qqic < 128) {
-		mc_qqi = mlh2->mld2q_qqic;
-	} else {
-		unsigned long mc_man, mc_exp;
-
-		mc_exp = MLDV2_QQIC_EXP(mlh2->mld2q_qqic);
-		mc_man = MLDV2_QQIC_MAN(mlh2->mld2q_qqic);
-
-		mc_qqi = (mc_man | 0x10) << (mc_exp + 3);
-	}
-
-	idev->mc_qi = mc_qqi * HZ;
+	idev->mc_qi = mldv2_qqi(mlh2) * HZ;
 }
 
 static void mld_update_qri(struct inet6_dev *idev,
@@ -1338,7 +1325,7 @@ static void mld_update_qri(struct inet6_dev *idev,
 	 *  - 5.1.3. Maximum Response Code
 	 *  - 9.3. Query Response Interval
 	 */
-	idev->mc_qri = msecs_to_jiffies(mldv2_mrc(mlh2));
+	idev->mc_qri = msecs_to_jiffies(mldv2_mrd(mlh2));
 }
 
 static int mld_process_v1(struct inet6_dev *idev, struct mld_msg *mld,
@@ -1390,7 +1377,7 @@ static int mld_process_v1(struct inet6_dev *idev, struct mld_msg *mld,
 static void mld_process_v2(struct inet6_dev *idev, struct mld2_query *mld,
 			   unsigned long *max_delay)
 {
-	*max_delay = max(msecs_to_jiffies(mldv2_mrc(mld)), 1UL);
+	*max_delay = max(msecs_to_jiffies(mldv2_mrd(mld)), 1UL);
 
 	mld_update_qrv(idev, mld);
 	mld_update_qi(idev, mld);
-- 
2.43.0


^ permalink raw reply related

* [PATCH net-next v3 1/5] ipv4: igmp: get rid of IGMPV3_{QQIC,MRC} and simplify calculation
From: Ujjal Roy @ 2026-04-03 15:00 UTC (permalink / raw)
  To: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Nikolay Aleksandrov, Ido Schimmel, David Ahern,
	Shuah Khan, Andy Roulin, Yong Wang, Petr Machata
  Cc: Ujjal Roy, bridge, netdev, linux-kernel, linux-kselftest
In-Reply-To: <20260403150050.1235-1-royujjal@gmail.com>

Get rid of the IGMPV3_MRC macro and use the igmpv3_mrt() API to
calculate the Max Resp Time from the Maximum Response Code.

Similarly, for IGMPV3_QQIC, use the igmpv3_qqi() API to calculate
the Querier's Query Interval from the QQIC field.

Signed-off-by: Ujjal Roy <royujjal@gmail.com>
---
 include/linux/igmp.h      | 84 +++++++++++++++++++++++++++++++++++----
 net/bridge/br_multicast.c |  2 +-
 net/ipv4/igmp.c           |  6 +--
 3 files changed, 80 insertions(+), 12 deletions(-)

diff --git a/include/linux/igmp.h b/include/linux/igmp.h
index 073b30a9b850..0624410e75c6 100644
--- a/include/linux/igmp.h
+++ b/include/linux/igmp.h
@@ -92,15 +92,83 @@ struct ip_mc_list {
 	struct rcu_head		rcu;
 };
 
+/* RFC3376, relevant sections:
+ *  - 4.1.1. Maximum Response Code
+ *  - 4.1.7. QQIC (Querier's Query Interval Code)
+ *
+ * For both MRC and QQIC, values >= 128 use the same floating-point
+ * encoding as follows:
+ *
+ *  0 1 2 3 4 5 6 7
+ * +-+-+-+-+-+-+-+-+
+ * |1| exp | mant  |
+ * +-+-+-+-+-+-+-+-+
+ */
+#define IGMPV3_FP_EXP(value)		(((value) >> 4) & 0x07)
+#define IGMPV3_FP_MAN(value)		((value) & 0x0f)
+
+/* IGMPV3 floating-point exponential field threshold */
+#define IGMPV3_EXP_MIN_THRESHOLD	128
+
 /* V3 exponential field decoding */
-#define IGMPV3_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value))
-#define IGMPV3_EXP(thresh, nbmant, nbexp, value) \
-	((value) < (thresh) ? (value) : \
-        ((IGMPV3_MASK(value, nbmant) | (1<<(nbmant))) << \
-         (IGMPV3_MASK((value) >> (nbmant), nbexp) + (nbexp))))
-
-#define IGMPV3_QQIC(value) IGMPV3_EXP(0x80, 4, 3, value)
-#define IGMPV3_MRC(value) IGMPV3_EXP(0x80, 4, 3, value)
+
+/* IGMPv3 QQIC/MRC 8-bit exponential field decode.
+ *
+ * RFC3376, 4.1.1 & 4.1.7. defines the decoding formula:
+ *      0 1 2 3 4 5 6 7
+ *     +-+-+-+-+-+-+-+-+
+ *     |1| exp | mant  |
+ *     +-+-+-+-+-+-+-+-+
+ * Max Resp Time = (mant | 0x10) << (exp + 3)
+ * QQI = (mant | 0x10) << (exp + 3)
+ */
+static inline unsigned long igmpv3_exp_field_decode(const u8 code)
+{
+	/* RFC3376, relevant sections:
+	 *  - 4.1.1. Maximum Response Code
+	 *  - 4.1.7. QQIC (Querier's Query Interval Code)
+	 */
+	if (code < IGMPV3_EXP_MIN_THRESHOLD) {
+		return code;
+	} else {
+		unsigned long mc_man, mc_exp;
+
+		mc_exp = IGMPV3_FP_EXP(code);
+		mc_man = IGMPV3_FP_MAN(code);
+
+		return (mc_man | 0x10) << (mc_exp + 3);
+	}
+}
+
+/* Calculate Max Resp Time from Maximum Response Code
+ *
+ * After decode, MRC represents the Maximum Response Time (MRT) in units
+ * of 0.1 seconds (100 ms).
+ */
+static inline unsigned long igmpv3_mrt(const struct igmpv3_query *ih3)
+{
+	/* RFC3376, relevant sections:
+	 *  - 4.1.1. Maximum Response Code
+	 *  - 8.3. Query Response Interval
+	 */
+	return igmpv3_exp_field_decode(ih3->code);
+}
+
+/* Calculate Querier's Query Interval from Querier's Query Interval Code
+ *
+ * After decode, QQIC represents the Querier's Query Interval in units
+ * of seconds.
+ */
+static inline unsigned long igmpv3_qqi(const struct igmpv3_query *ih3)
+{
+	/* RFC3376, relevant sections:
+	 *  - 4.1.7. QQIC (Querier's Query Interval Code)
+	 *  - 8.2. Query Interval
+	 *  - 8.12. Older Version Querier Present Timeout
+	 *    (the [Query Interval] in the last Query received)
+	 */
+	return igmpv3_exp_field_decode(ih3->qqic);
+}
 
 static inline int ip_mc_may_pull(struct sk_buff *skb, unsigned int len)
 {
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 881d866d687a..9fec76e887bc 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -3518,7 +3518,7 @@ static void br_ip4_multicast_query(struct net_bridge_mcast *brmctx,
 			goto out;
 
 		max_delay = ih3->code ?
-			    IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;
+			    igmpv3_mrt(ih3) * (HZ / IGMP_TIMER_SCALE) : 1;
 	} else {
 		goto out;
 	}
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index a674fb44ec25..d7eff36d98c3 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -991,7 +991,7 @@ static bool igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
 		 * different encoding. We use the v3 encoding as more likely
 		 * to be intended in a v3 query.
 		 */
-		max_delay = IGMPV3_MRC(ih3->code)*(HZ/IGMP_TIMER_SCALE);
+		max_delay = igmpv3_mrt(ih3) * (HZ / IGMP_TIMER_SCALE);
 		if (!max_delay)
 			max_delay = 1;	/* can't mod w/ 0 */
 	} else { /* v3 */
@@ -1006,7 +1006,7 @@ static bool igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
 			ih3 = igmpv3_query_hdr(skb);
 		}
 
-		max_delay = IGMPV3_MRC(ih3->code)*(HZ/IGMP_TIMER_SCALE);
+		max_delay = igmpv3_mrt(ih3) * (HZ / IGMP_TIMER_SCALE);
 		if (!max_delay)
 			max_delay = 1;	/* can't mod w/ 0 */
 		WRITE_ONCE(in_dev->mr_maxdelay, max_delay);
@@ -1016,7 +1016,7 @@ static bool igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
 		 * configured value.
 		 */
 		in_dev->mr_qrv = ih3->qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
-		in_dev->mr_qi = IGMPV3_QQIC(ih3->qqic)*HZ ?: IGMP_QUERY_INTERVAL;
+		in_dev->mr_qi = igmpv3_qqi(ih3) * HZ ? : IGMP_QUERY_INTERVAL;
 
 		/* RFC3376, 8.3. Query Response Interval:
 		 * The number of seconds represented by the [Query Response
-- 
2.43.0


^ permalink raw reply related

* [PATCH net-next v3 0/5] net: bridge: mcast: support exponential field encoding
From: Ujjal Roy @ 2026-04-03 15:00 UTC (permalink / raw)
  To: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Nikolay Aleksandrov, Ido Schimmel, David Ahern,
	Shuah Khan, Andy Roulin, Yong Wang, Petr Machata
  Cc: Ujjal Roy, bridge, netdev, linux-kernel, linux-kselftest

Description:
This series addresses a mismatch in how multicast query
intervals and response codes are handled across IPv4 (IGMPv3)
and IPv6 (MLDv2). While decoding logic currently exists,
the corresponding encoding logic is missing during query
packet generation. This leads to incorrect intervals being
transmitted when values exceed their linear thresholds.

The patches introduce a unified floating-point encoding
approach based on RFC3376 and RFC3810, ensuring that large
intervals are correctly represented in QQIC and MRC fields
using the exponent-mantissa format.

Key Changes:
* ipv4: igmp: get rid of IGMPV3_{QQIC,MRC} and simplify calculation
  Removes legacy macros in favor of a cleaner, unified
  calculation for retrieving intervals from encoded fields,
  improving code maintainability.

* ipv6: mld: rename mldv2_mrc() and add mldv2_qqi()
  Standardizes MLDv2 terminology by renaming mldv2_mrc()
  to mldv2_mrd() (Maximum Response Delay) and introducing
  a new API mldv2_qqi for QQI calculation, improving code
  readability.

* ipv4: igmp: encode multicast exponential fields
  Introduces the logic to dynamically calculate the exponent
  and mantissa using bit-scan (fls). This ensures QQIC and
  MRC fields (8-bit) are properly encoded when transmitting
  query packets with intervals that exceed their respective
  linear threshold value of 128 (for QQI/MRT).

* ipv6: mld: encode multicast exponential fields
  Applies similar encoding logic for MLDv2. This ensures
  QQIC (8-bit) and MRC (16-bit) fields are properly encoded
  when transmitting query packets with intervals that exceed
  their respective linear thresholds (128 for QQI; 32768
  for MRD).

* selftests: net: bridge: add tests for MRC and QQIC validation
  Updates bridge selftests to validate both linear and non-linear
  (exponential) encoding for MRC and QQIC fields, ensuring
  protocol compliance across IGMPv3 and MLDv2.

Impact:
These changes ensure that multicast queriers and listeners
stay synchronized on timing intervals, preventing protocol
timeouts or premature group membership expiration caused
by incorrectly formatted packet headers.

Test results:
Giving results only from vlmc_query_intvl_test and vlmc_query_response_intvl_test
of the script bridge_vlan_mcast.sh.
Without patchset, here is the result.
    - TEST: Vlan multicast snooping enable                                [ OK ]
    - TEST: Vlan mcast_query_interval global option default value         [ OK ]
    - Vlan 10 mcast_query_interval (QQIC) test cases:
    - TEST: Number of tagged IGMPv2 general query                         [ OK ]
    - TEST: IGMPv3 QQIC linear value 60                                   [ OK ]
    - TEST: MLDv2 QQIC linear value 60                                    [ OK ]
    - TEST: IGMPv3 QQIC non linear value 160                              [FAIL]
    -         Wrong QQIC in sent tagged IGMPv3 general queries
    - TEST: MLDv2 QQIC non linear value 160                               [FAIL]
    -         Wrong QQIC in sent tagged MLDv2 general queries
    - TEST: Vlan mcast_query_response_interval global option default value   [ OK ]
    - Vlan 10 mcast_query_response_interval (MRC) test cases:
    - TEST: IGMPv3 MRC linear value 60                                    [ OK ]
    - TEST: IGMPv3 MRC non linear value 160                               [FAIL]
    -         Wrong MRC in sent tagged IGMPv3 general queries
    - TEST: MLDv2 MRC linear value 30000                                  [ OK ]
    - TEST: MLDv2 MRC non linear value 60000                              [FAIL]
    -         Wrong MRC in sent tagged MLDv2 general queries
With these patchset, here is the result.
    * TEST: Vlan multicast snooping enable                                [ OK ]
    * TEST: Vlan mcast_query_interval global option default value         [ OK ]
    * Vlan 10 mcast_query_interval (QQIC) test cases:
    * TEST: Number of tagged IGMPv2 general query                         [ OK ]
    * TEST: IGMPv3 QQIC linear value 60                                   [ OK ]
    * TEST: MLDv2 QQIC linear value 60                                    [ OK ]
    * TEST: IGMPv3 QQIC non linear value 160                              [ OK ]
    * TEST: MLDv2 QQIC non linear value 160                               [ OK ]
    * TEST: Vlan mcast_query_response_interval global option default value   [ OK ]
    * Vlan 10 mcast_query_response_interval (MRC) test cases:
    * TEST: IGMPv3 MRC linear value 60                                    [ OK ]
    * TEST: IGMPv3 MRC non linear value 160                               [ OK ]
    * TEST: MLDv2 MRC linear value 30000                                  [ OK ]
    * TEST: MLDv2 MRC non linear value 60000                              [ OK ]

v3:
- Updated the series title for better clarity; old one is here
  https://lore.kernel.org/all/20260326150742.50289-1-royujjal@gmail.com/
- Added key changes section for new selftests patch
- Updated netdev style comments and addressed review comments
- Fixed MLDv2 MRC conversion logic during query generation
- Mentioned intervals in units wherever applicable
- Dropped type casting and fixed indentations

v2:
- Retargeted the series to net-next as suggested
- Fixed a compilation warning in the MLD rename change
- Kept reverse xmas tree order in IGMP exponential encoding change
- Added bridge selftests to validate IGMPv3 Query MRC and QQIC handling

Ujjal Roy (5):
  ipv4: igmp: get rid of IGMPV3_{QQIC,MRC} and simplify calculation
  ipv6: mld: rename mldv2_mrc() and add mldv2_qqi()
  ipv4: igmp: encode multicast exponential fields
  ipv6: mld: encode multicast exponential fields
  selftests: net: bridge: add tests for MRC and QQIC validation

 include/linux/igmp.h                          | 171 +++++++++++++++-
 include/net/mld.h                             | 190 +++++++++++++++++-
 net/bridge/br_multicast.c                     |  22 +-
 net/ipv4/igmp.c                               |   6 +-
 net/ipv6/mcast.c                              |  19 +-
 .../selftests/net/forwarding/.gitignore       |   2 +
 .../testing/selftests/net/forwarding/Makefile |  10 +
 .../net/forwarding/bridge_vlan_mcast.sh       | 157 ++++++++++++++-
 .../selftests/net/forwarding/mc_decode.c      |  73 +++++++
 .../selftests/net/forwarding/mc_encode.c      |  78 +++++++
 10 files changed, 675 insertions(+), 53 deletions(-)
 create mode 100644 tools/testing/selftests/net/forwarding/mc_decode.c
 create mode 100644 tools/testing/selftests/net/forwarding/mc_encode.c


base-commit: 8b0e64d6c9e7feec5ba5643b4fa8b7fd54464778
-- 
2.43.0


^ permalink raw reply

* Re: [PATCH-next v2 0/2] ipvs: Fix incorrect use of HK_TYPE_KTHREAD housekeeping cpumask
From: Julian Anastasov @ 2026-04-03 15:00 UTC (permalink / raw)
  To: Pablo Neira Ayuso
  Cc: Waiman Long, Simon Horman, David S. Miller, David Ahern,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Florian Westphal,
	Phil Sutter, Frederic Weisbecker, Chen Ridong, Phil Auld,
	linux-kernel, netdev, lvs-devel, netfilter-devel, coreteam,
	sheviks
In-Reply-To: <ac_OscBPYRwt73ic@lemonverbena>


	Hello,

On Fri, 3 Apr 2026, Pablo Neira Ayuso wrote:

> On Fri, Apr 03, 2026 at 05:15:50PM +0300, Julian Anastasov wrote:
> > 
> > 	Hello,
> > 
> > On Tue, 31 Mar 2026, Waiman Long wrote:
> > 
> > >  v2:
> > >   - Rebased on top of linux-next
> > > 
> > > Since commit 041ee6f3727a ("kthread: Rely on HK_TYPE_DOMAIN for preferred
> > > affinity management"), the HK_TYPE_KTHREAD housekeeping cpumask may no
> > > longer be correct in showing the actual CPU affinity of kthreads that
> > > have no predefined CPU affinity. As the ipvs networking code is still
> > > using HK_TYPE_KTHREAD, we need to make HK_TYPE_KTHREAD reflect the
> > > reality.
> > > 
> > > This patch series makes HK_TYPE_KTHREAD an alias of HK_TYPE_DOMAIN
> > > and uses RCU to protect access to the HK_TYPE_KTHREAD housekeeping
> > > cpumask.
> > > 
> > > Waiman Long (2):
> > >   sched/isolation: Make HK_TYPE_KTHREAD an alias of HK_TYPE_DOMAIN
> > >   ipvs: Guard access of HK_TYPE_KTHREAD cpumask with RCU
> > 
> > 	The patchset looks good to me for nf-next, thanks!
> > 
> > Acked-by: Julian Anastasov <ja@ssi.bg>
> > 
> > 	Pablo, Florian, as a bugfix this patchset missed
> > the chance to be applied before the changes that are in
> > nf-next in ip_vs.h, there is little fuzz there. If there
> > is no chance to resolve it somehow, we can apply it
> > on top of nf-next where it now applies successfully.
> 
> One way to handle this is to follow up with nf-next as you suggest,
> then send a backport that applies cleanly for -stable once it is
> released.

	Lets do it this way, thanks!

> Else, let me know if I am misunderstanding.

Regards

--
Julian Anastasov <ja@ssi.bg>


^ permalink raw reply

* Re: [PATCH net] bridge: guard local VLAN-0 FDB helpers against NULL vlan group
From: Nikolay Aleksandrov @ 2026-04-03 14:59 UTC (permalink / raw)
  To: Zijing Yin, netdev
  Cc: bridge, idosch, davem, edumazet, kuba, pabeni, horms, nathan,
	nick.desaulniers+lkml, morbo, justinstitt, petrm, linux-kernel,
	llvm
In-Reply-To: <20260402140153.3925663-1-yzjaurora@gmail.com>

On 02/04/2026 17:01, Zijing Yin wrote:
> When CONFIG_BRIDGE_VLAN_FILTERING is not set, br_vlan_group() and
> nbp_vlan_group() return NULL (br_private.h stub definitions). The
> BR_BOOLOPT_FDB_LOCAL_VLAN_0 toggle code is compiled unconditionally and
> reaches br_fdb_delete_locals_per_vlan_port() and
> br_fdb_insert_locals_per_vlan_port(), where the NULL vlan group pointer
> is dereferenced via list_for_each_entry(v, &vg->vlan_list, vlist).
> 
> The observed crash is in the delete path, triggered when creating a
> bridge with IFLA_BR_MULTI_BOOLOPT containing BR_BOOLOPT_FDB_LOCAL_VLAN_0
> via RTM_NEWLINK. The insert helper has the same bug pattern.
> 
>    Oops: general protection fault, probably for non-canonical address 0xdffffc0000000056: 0000 [#1] KASAN NOPTI
>    KASAN: null-ptr-deref in range [0x00000000000002b0-0x00000000000002b7]
>    RIP: 0010:br_fdb_delete_locals_per_vlan+0x2b9/0x310
>    Call Trace:
>     br_fdb_toggle_local_vlan_0+0x452/0x4c0
>     br_toggle_fdb_local_vlan_0+0x31/0x80 net/bridge/br.c:276
>     br_boolopt_toggle net/bridge/br.c:313
>     br_boolopt_multi_toggle net/bridge/br.c:364
>     br_changelink net/bridge/br_netlink.c:1542
>     br_dev_newlink net/bridge/br_netlink.c:1575
> 
> Add NULL checks for the vlan group pointer in both helpers, returning
> early when there are no VLANs to iterate. This matches the existing
> pattern used by other bridge FDB functions such as br_fdb_add() and
> br_fdb_delete().
> 
> Fixes: 21446c06b441 ("net: bridge: Introduce UAPI for BR_BOOLOPT_FDB_LOCAL_VLAN_0")
> Signed-off-by: Zijing Yin <yzjaurora@gmail.com>
> ---
> Tested on Linux v7.0-rc5 (upstream tag) with clang 20.1.0, KASAN
> enabled, CONFIG_BRIDGE_VLAN_FILTERING=n.
> 
> Bug independently reproduced with the attached C reproducer
> (repro_br_fdb.c). The crash triggers deterministically on the first
> run with CONFIG_BRIDGE_VLAN_FILTERING=n on a clang-built kernel.
> 
> Exact crash signature from reproduction:
> 
>    Oops: general protection fault, probably for non-canonical address 0xdffffc0000000056: 0000 [#1] KASAN NOPTI
>    KASAN: null-ptr-deref in range [0x00000000000002b0-0x00000000000002b7]
>    RIP: 0010:br_fdb_delete_locals_per_vlan+0x72/0x3f0
>    Call Trace:
>     br_fdb_toggle_local_vlan_0+0x3d/0x1d0
>     br_boolopt_toggle+0xba/0x1a0
>     br_boolopt_multi_toggle+0x129/0x250
>     br_changelink+0x1100/0x1490
>     br_dev_newlink+0x115/0x190
>     rtnl_newlink+0xe15/0x25c0
> 
> Note: gcc 13.3 with the same config optimizes away the NULL dereference
> path (UB elimination), so the crash does not trigger on gcc-built
> kernels. The code is still incorrect regardless of compiler behavior.
> 
> Reproducer (C source): [PASTE_URL_HERE]
> Kernel .config:        [PASTE_URL_HERE]
> 
> To reproduce: compile the C reproducer with `gcc -static -o repro repro.c`,
> run as root on a clang-built kernel. The crash triggers during
> br_dev_newlink() -> br_changelink() when the boolopt toggle reaches
> br_fdb_delete_locals_per_vlan_port() with a NULL vlan group. Note:
> RTM_SETLINK on an existing bridge may not trigger it due to different
> code ordering.
> 
>   net/bridge/br_fdb.c | 6 ++++++
>   1 file changed, 6 insertions(+)
> 
> diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
> index 0501ffcb8..e2c17f620 100644
> --- a/net/bridge/br_fdb.c
> +++ b/net/bridge/br_fdb.c
> @@ -597,6 +597,9 @@ static void br_fdb_delete_locals_per_vlan_port(struct net_bridge *br,
>   		dev = br->dev;
>   	}
>   
> +	if (!vg)
> +		return;
> +
>   	list_for_each_entry(v, &vg->vlan_list, vlist)
>   		br_fdb_find_delete_local(br, p, dev->dev_addr, v->vid);
>   }
> @@ -630,6 +633,9 @@ static int br_fdb_insert_locals_per_vlan_port(struct net_bridge *br,
>   		dev = br->dev;
>   	}
>   
> +	if (!vg)
> +		return 0;
> +
>   	list_for_each_entry(v, &vg->vlan_list, vlist) {
>   		if (!br_vlan_should_use(v))
>   			continue;

Acked-by: Nikolay Aleksandrov <razor@blackwall.org>


^ permalink raw reply

* Re: [PATCH net-next v2] ppp: add IFLA_PPP_UNIT netlink attribute
From: Pali Rohár @ 2026-04-03 14:58 UTC (permalink / raw)
  To: Martin Olivier, Qingfang Deng
  Cc: netdev, linux-ppp, andrew+netdev, davem, edumazet, kuba, pabeni,
	linux-kernel, Paul Mackerras, Guillaume Nault
In-Reply-To: <20260318100738.vcnp7kntuzavyula@pali>

On Wednesday 18 March 2026 11:07:38 Pali Rohár wrote:
> On Wednesday 18 March 2026 09:59:29 Qingfang Deng wrote:
> > On Sat, 14 Mar 2026 02:14:29 +0100, Martin Olivier wrote:
> > > Currently, the PPP rtnetlink API allows creating a new network interface
> > > with a custom ifname, but it lacks the ability to specify a custom PPP
> > > unit id.
> > > 
> > > Setting a specific unit id is currently only possible with the
> > > PPPIOCNEWUNIT ioctl. If a user-space program also requires a custom
> > > interface name, it must create the interface first with PPPIOCNEWUNIT
> > > and then rename it.
> > > 
> > > Resolve this by introducing the IFLA_PPP_UNIT netlink attribute. This
> > > allows user-space programs to atomically request both a custom ifname
> > > and a specific PPP unit id during the RTM_NEWLINK creation process,
> > > eliminating the post-creation renaming for this use case.
> > > 
> > > Signed-off-by: Martin Olivier <martin.olivier@live.fr>
> > > ---
> > > Changes in v2:
> > > - use nl policy to set IFLA_PPP_UNIT min allowed value instead of a manual check in ppp_nl_validate()
> > > - use of nla_get_s32_default() to collect IFLA_PPP_UNIT value
> > > Link to v1: https://lore.kernel.org/netdev/PAWP192MB2411A5E7D3BE1B55E155A92F9747A@PAWP192MB2411.EURP192.PROD.OUTLOOK.COM/
> > 
> > The patch itself looks good to me, but I would like to check the
> > userspace changes too. Please create a pull request at
> > https://github.com/ppp-project/ppp/pulls
> > 
> > +Cc: Paul Mackerras, Guillaume Nault, Pali Rohár
> > 
> > Regards,
> > Qingfang
> 
> Hello Martin, in past I have sent similar change:
> https://lore.kernel.org/linux-ppp/20210807163749.18316-1-pali@kernel.org/T/#u
> Look at the discussion, it can be useful to understand why the change
> was not accepted.

Anyway, if you want to continue on this patch, here are my points for review:

- I would suggest to use IFLA_PPP_UNIT_ID name for consistency. We
  already have IFLA_PPP_DEV_FD value where is FD suffix which is saying
  what it is. So for naming consistency is the suffix "_ID" useful.

- Allow to specify -1 as an valid input. Currently the
  NLA_POLICY_MIN(NLA_S32, 0) does not allow -1.
  -1 should work as a default value, like if the value is not specified
  at all.

- Add #define IFLA_PPP_UNIT_ID ifla_ppp_unit_id into the enum { ... } in
  if_link.h. This is for userspace compatibility, which can check fi
  the IFLA_PPP_UNIT_ID is provided or not (via #ifdef).

- Do not rewrite error to -EEXIST when calling the ppp_dev_configure()
  from the ppp_nl_newlink() with specified unit_id. ppp_nl_newlink() is
  a new code path which will allow to specify unit_id, and hence it is
  not useful to hide a real error and replace it by -EEXIST.

All of these points I have already handled in my version of the patch
which I sent and is available in the above link. So you can use it as an
inspiration how to easily handle them.

Pali

^ permalink raw reply

* Re: Re: [RFC PATCH 0/6] rust: net: introduce minimal rtnl/netdevice abstractions and nlmon reference driver
From: Andrew Lunn @ 2026-04-03 14:56 UTC (permalink / raw)
  To: wenzhaoliao
  Cc: rust-for-linux, netdev, linux-kernel, ojeda, boqun, gary,
	bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, dakr,
	andrew+netdev, davem, edumazet, kuba, pabeni
In-Reply-To: <APYAlQCNKK5EzEq6n4bgjqou.3.1775205609812.Hmail.2023000929@ruc.edu.cn>

On Fri, Apr 03, 2026 at 04:40:09PM +0800, wenzhaoliao wrote:
> Hi Andrew,
> 
> Thank you for the candid feedback. I completely understand and agree with your
> point. Introducing Rust just for the sake of rewriting existing, perfectly
> working C code is not the goal here.
> 
> To clarify, my primary motivation for submitting the nlmon driver was not to
> replace the C implementation, but rather to use it as a minimal, isolated
> testbed to validate the proposed Rust networking abstractions (the first part
> of the patch series). I wanted to ensure the abstractions were somewhat
> grounded in a real use case before attempting to write a driver for a
> completely new device.

We prefer to see real users of newly added code. So start implementing
this new drivers for new hardware. Introduce the Rust abstractions as
the driver needs them. We allow patchsets of up to 15 patches. And the
first patchset does not need to be a functioning driver. So implement
what you can within 15 patches. It does not matter if it does not even
send/receive frames. Maybe it will just probe, and setup the Rx and Tx
rings? Then submit another patchset of 15 patches, adding more
abstractions and using them in the driver. Eventually you will get to
a working very minimal driver.

You might want to be way ahead in terms of development compared to
submission. So you might have 45 to 60 patches in your tree, a very
minimum driver which you know actually works, and then start
submitting. But expect to be doing a lot of rewriting as you get
review comments.

What hardware do you have in mind?

	Andrew

^ permalink raw reply

* Re: [PATCH net] net: phy: micrel: Fix MMD register access during SPD in ksz9131_resume()
From: Russell King (Oracle) @ 2026-04-03 14:53 UTC (permalink / raw)
  To: Ovidiu Panait
  Cc: andrew, hkallweit1, davem, edumazet, kuba, pabeni, biju.das.jz,
	netdev, linux-kernel, linux-renesas-soc
In-Reply-To: <20260403111738.37749-1-ovidiu.panait.rb@renesas.com>

On Fri, Apr 03, 2026 at 11:17:38AM +0000, Ovidiu Panait wrote:
> During system suspend, phy_suspend() puts the PHY into Software Power-Down
> (SPD) by setting the BMCR_PDOWN bit in MII_BMCR. According to the KSZ9131
> datasheet, MMD register access is restricted during SPD:
> 
>   - Only access to the standard registers (0 through 31) is supported.
>   - Access to MMD address spaces other than MMD address space 1 is
>     possible if the spd_clock_gate_override bit is set.
>   - Access to MMD address space 1 is not possible.
> 
> However, ksz9131_resume() calls ksz9131_config_rgmii_delay() before
> kszphy_resume() clears BMCR_PDOWN. This means MMD registers are accessed
> while the PHY is still in SPD, contrary to the datasheet.
> 
> Additionally, on platforms where the PHY loses power during suspend
> (e.g. RZ/G3E), all settings from ksz9131_config_init(), not just the
> RGMII delays, are lost and need to be restored. When the MAC driver
> sets mac_managed_pm (e.g. stmmac), mdio_bus_phy_resume() is skipped,
> so phy_init_hw() (which calls config_init to restore all PHY settings)
> is never invoked during resume.
> 
> Fix this by replacing the RGMII delay restoration with a call to
> phy_init_hw(), which takes the PHY out of SPD and performs full
> reinitialization.
> 
> Fixes: f25a7eaa897f ("net: phy: micrel: Add ksz9131_resume()")
> Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>
> ---
>  drivers/net/phy/micrel.c | 9 +++++++--
>  1 file changed, 7 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
> index 2aa1dedd21b8..4236dbf4ad6b 100644
> --- a/drivers/net/phy/micrel.c
> +++ b/drivers/net/phy/micrel.c
> @@ -6016,8 +6016,13 @@ static int lan8841_suspend(struct phy_device *phydev)
>  
>  static int ksz9131_resume(struct phy_device *phydev)
>  {
> -	if (phydev->suspended && phy_interface_is_rgmii(phydev))
> -		ksz9131_config_rgmii_delay(phydev);
> +	int ret;
> +
> +	if (phydev->suspended) {
> +		ret = phy_init_hw(phydev);
> +		if (ret)
> +			return ret;
> +	}
>  
>  	return kszphy_resume(phydev);
>  }

mdio_bus_phy_resume():

        ret = phy_init_hw(phydev);
        if (ret < 0)
                return ret;

        ret = phy_resume(phydev);
        if (ret < 0)
                return ret;

where phy_resume() calls your resume function.

If a MAC driver is handling suspend/resume by setting
phydev->mac_managed_pm then maybe the MAC driver should also be
issuing phy_init_hw() before calling phy_resume() ?

Which MAC driver are you seeing a problem with?

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!

^ permalink raw reply

* Re: [PATCH v9 07/10] x86/vmscape: Use static_call() for predictor flush
From: Sean Christopherson @ 2026-04-03 14:52 UTC (permalink / raw)
  To: Pawan Gupta
  Cc: x86, Jon Kohler, Nikolay Borisov, H. Peter Anvin, Josh Poimboeuf,
	David Kaplan, Borislav Petkov, Dave Hansen, Peter Zijlstra,
	Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, KP Singh,
	Jiri Olsa, David S. Miller, David Laight, Andy Lutomirski,
	Thomas Gleixner, Ingo Molnar, David Ahern, Martin KaFai Lau,
	Eduard Zingerman, Song Liu, Yonghong Song, John Fastabend,
	Stanislav Fomichev, Hao Luo, Paolo Bonzini, Jonathan Corbet,
	linux-kernel, kvm, Asit Mallick, Tao Zhang, bpf, netdev,
	linux-doc
In-Reply-To: <20260402-vmscape-bhb-v9-7-94d16bc29774@linux.intel.com>

On Thu, Apr 02, 2026, Pawan Gupta wrote:
> Adding more mitigation options at exit-to-userspace for VMSCAPE would
> usually require a series of checks to decide which mitigation to use. In
> this case, the mitigation is done by calling a function, which is decided
> at boot. So, adding more feature flags and multiple checks can be avoided
> by using static_call() to the mitigating function.
> 
> Replace the flag-based mitigation selector with a static_call(). This also
> frees the existing X86_FEATURE_IBPB_EXIT_TO_USER.

...

> @@ -3133,8 +3139,14 @@ static void __init vmscape_update_mitigation(void)
>  static void __init vmscape_apply_mitigation(void)
>  {
>  	if (vmscape_mitigation == VMSCAPE_MITIGATION_IBPB_EXIT_TO_USER)
> -		setup_force_cpu_cap(X86_FEATURE_IBPB_EXIT_TO_USER);
> +		static_call_update(vmscape_predictor_flush, write_ibpb);
> +}
> +
> +bool vmscape_mitigation_enabled(void)
> +{
> +	return !!static_call_query(vmscape_predictor_flush);
>  }
> +EXPORT_SYMBOL_FOR_KVM(vmscape_mitigation_enabled);
>  
>  #undef pr_fmt
>  #define pr_fmt(fmt) fmt
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 45d7cfedc507..e204482e64f3 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -11463,7 +11463,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
>  	 * set for the CPU that actually ran the guest, and not the CPU that it
>  	 * may migrate to.
>  	 */
> -	if (cpu_feature_enabled(X86_FEATURE_IBPB_EXIT_TO_USER))
> +	if (vmscape_mitigation_enabled())

This is pretty lame.  It turns a statically patched MOV

  11548		if (cpu_feature_enabled(X86_FEATURE_IBPB_EXIT_TO_USER))
  11549			this_cpu_write(x86_ibpb_exit_to_user, true);
     0x000000000003c57a <+858>:	movb   $0x1,%gs:0x0(%rip)        # 0x3c582 <vcpu_enter_guest+866>

into a function call and two sets of conditional branches.  And with mitigations
enabled, that function call may trigger the wonderful unret insanity

  11548		if (vmscape_mitigation_enabled())
     0x000000000003c575 <+853>:	call   0x3c57a <vcpu_enter_guest+858>
     0x000000000003c57a <+858>:	test   %al,%al
     0x000000000003c57c <+860>:	je     0x3c586 <vcpu_enter_guest+870>

  11549			this_cpu_write(x86_predictor_flush_exit_to_user, true);
     0x000000000003c57e <+862>:	movb   $0x1,%gs:0x0(%rip)        # 0x3c586 <vcpu_enter_guest+870>


  3166	{
     0xffffffff81285320 <+0>:	endbr64
     0xffffffff81285324 <+4>:	call   0xffffffff812aa5a0 <__fentry__>

  3167		return !!static_call_query(vmscape_predictor_flush);
     0xffffffff81285329 <+9>:	mov    0x13a4f30(%rip),%rax        # 0xffffffff8262a260 <__SCK__vmscape_predictor_flush>
     0xffffffff81285330 <+16>:	test   %rax,%rax
     0xffffffff81285333 <+19>:	setne  %al

  3168	}
     0xffffffff81285336 <+22>:	jmp    0xffffffff81db1e30 <__x86_return_thunk>

While this isn't KVM's super hot inner run loop, it's still very much a hot path.
Even more annoying, KVM will eat the function call on kernels with CPU_MITIGATIONS=n.

I'd like to at least do something like the below to make the common case of
multiple guest entry/exits more or less free, and to avoid the CALL+(UN)RET
overhead, but trying to include linux/static_call.h in processor.h (or any other
core x86 header) creates a cyclical dependency :-/

diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 20ab4dd588c6..0dc0680a80f8 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -36,6 +36,7 @@ struct vm86;
 #include <linux/err.h>
 #include <linux/irqflags.h>
 #include <linux/mem_encrypt.h>
+#include <linux/static_call.h>
 
 /*
  * We handle most unaligned accesses in hardware.  On the other hand
@@ -753,7 +754,11 @@ enum mds_mitigations {
 };
 
 extern bool gds_ucode_mitigated(void);
-extern bool vmscape_mitigation_enabled(void);
+
+static inline bool vmscape_mitigation_enabled(void)
+{
+       return !!static_call_query(vmscape_predictor_flush);
+}
 
 /*
  * Make previous memory operations globally visible before
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index 366ebe1e1fb9..02bf626f0773 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -148,6 +148,7 @@ DEFINE_STATIC_KEY_FALSE(switch_mm_cond_l1d_flush);
  * sequence. This defaults to no mitigation.
  */
 DEFINE_STATIC_CALL_NULL(vmscape_predictor_flush, write_ibpb);
+EXPORT_STATIC_CALL_GPL(vmscape_predictor_flush);
 
 #undef pr_fmt
 #define pr_fmt(fmt)    "mitigations: " fmt
@@ -3162,12 +3163,6 @@ static void __init vmscape_apply_mitigation(void)
                static_call_update(vmscape_predictor_flush, clear_bhb_loop_nofence);
 }
 
-bool vmscape_mitigation_enabled(void)
-{
-       return !!static_call_query(vmscape_predictor_flush);
-}
-EXPORT_SYMBOL_FOR_KVM(vmscape_mitigation_enabled);
-
 #undef pr_fmt
 #define pr_fmt(fmt) fmt
 
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index a1fbbab08291..117c60d00758 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -11545,7 +11545,9 @@ static noinline int vcpu_enter_guest(struct kvm_vcpu *vcpu)
         * set for the CPU that actually ran the guest, and not the CPU that it
         * may migrate to.
         */
-       if (vmscape_mitigation_enabled())
+       if (IS_ENABLED(CONFIG_CPU_MITIGATIONS) &&
+           !this_cpu_read(x86_predictor_flush_exit_to_user) &&
+           vmscape_mitigation_enabled())
                this_cpu_write(x86_predictor_flush_exit_to_user, true);
 
        /*

^ permalink raw reply related

* Re: [PATCH net v2 2/2] selftests: seg6: add test for dst_cache isolation in seg6 lwtunnel
From: Andrea Mayer @ 2026-04-03 14:46 UTC (permalink / raw)
  To: Justin Iurman
  Cc: netdev, davem, edumazet, kuba, pabeni, horms, dsahern,
	david.lebrun, stefano.salsano, paolo.lungaroni, nicolas.dichtel,
	linux-kernel, Shuah Khan, linux-kselftest, Andrea Mayer
In-Reply-To: <d2b6a7fd-e09f-4e5d-838a-077ccecbd67f@gmail.com>

On Thu, 2 Apr 2026 20:35:12 +0200
Justin Iurman <justin.iurman@gmail.com> wrote:

> On 4/1/26 20:57, Andrea Mayer wrote:
> > Add a selftest that verifies the dst_cache in seg6 lwtunnel is not
> > shared between the input (forwarding) and output (locally generated)
> > paths.
> > 
> > The test creates three namespaces (ns_src, ns_router, ns_dst)
> > connected in a line. An SRv6 encap route on ns_router encapsulates
> > traffic destined to cafe::1 with SID fc00::100. The SID is
> > reachable only for forwarded traffic (from ns_src) via an ip rule
> > matching the ingress interface (iif veth-r0 lookup 100), and
> > blackholed in the main table.
> > 
> > The test verifies that:
> > 
> >    1. A packet generated locally on ns_router does not reach
> >       ns_dst with an empty cache, since the SID is blackholed;
> >    2. A forwarded packet from ns_src populates the input cache
> >       from table 100 and reaches ns_dst;
> >    3. A packet generated locally on ns_router still does not
> >       reach ns_dst after the input cache is populated,
> >       confirming the output path does not reuse the input
> >       cache entry.
> > 
> > Both the forwarded and local packets are pinned to the same CPU
> > with taskset, since dst_cache is per-cpu.
> > 

> > [snip]

> >
> > +test_cache_isolation()
> > +{
> > +	RET=0
> > +
> > +	# local ping with empty cache: must fail (SID is blackholed)
> > +	if ip netns exec "${NS_RTR}" taskset -c 0 \
> > +			ping6 -c 1 -W 2 "${DEST}" &>/dev/null; then
> > +		echo "SKIP: local ping succeeded, topology broken"
> > +		exit "${ksft_skip}"
> > +	fi
> > +
> > +	# forward from ns_src to populate the input cache
> > +	if ! ip netns exec "${NS_SRC}" taskset -c 0 \
> > +			ping6 -c 1 -W 2 "${DEST}" &>/dev/null; then
> > +		echo "SKIP: forwarded ping failed, topology broken"
> > +		exit "${ksft_skip}"
> > +	fi
> > +
> > +	# local ping again: must still fail; if the output path reuses
> > +	# the input cache, it bypasses the blackhole and the ping succeeds
> > +	if ip netns exec "${NS_RTR}" taskset -c 0 \
> > +			ping6 -c 1 -W 2 "${DEST}" &>/dev/null; then
> > +		echo "FAIL: output path used dst cached by input path"
> > +		RET="${ksft_fail}"
> > +	else
> > +		echo "PASS: output path dst_cache is independent"
> > +	fi
> > +
> > +	return "${RET}"
> > +}
> > +
> 
> We should check it runs as root here (e.g, required for netns creation).
> 
> if [ "$(id -u)" -ne 0 ]; then
> 	echo "SKIP: Need root privileges"
> 	exit "${ksft_skip}"
> fi
> 

Good catch! will fix in v3.

> Otherwise, LGTM:
> 
> Reviewed-by: Justin Iurman <justin.iurman@gmail.com>

Thanks for the review.

Ciao,
Andrea

^ permalink raw reply

* Re: [PATCH-next v2 0/2] ipvs: Fix incorrect use of HK_TYPE_KTHREAD housekeeping cpumask
From: Pablo Neira Ayuso @ 2026-04-03 14:29 UTC (permalink / raw)
  To: Julian Anastasov
  Cc: Waiman Long, Simon Horman, David S. Miller, David Ahern,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Florian Westphal,
	Phil Sutter, Frederic Weisbecker, Chen Ridong, Phil Auld,
	linux-kernel, netdev, lvs-devel, netfilter-devel, coreteam,
	sheviks
In-Reply-To: <cd9afe18-9862-6005-f7d9-d69425b7d4cf@ssi.bg>

On Fri, Apr 03, 2026 at 05:15:50PM +0300, Julian Anastasov wrote:
> 
> 	Hello,
> 
> On Tue, 31 Mar 2026, Waiman Long wrote:
> 
> >  v2:
> >   - Rebased on top of linux-next
> > 
> > Since commit 041ee6f3727a ("kthread: Rely on HK_TYPE_DOMAIN for preferred
> > affinity management"), the HK_TYPE_KTHREAD housekeeping cpumask may no
> > longer be correct in showing the actual CPU affinity of kthreads that
> > have no predefined CPU affinity. As the ipvs networking code is still
> > using HK_TYPE_KTHREAD, we need to make HK_TYPE_KTHREAD reflect the
> > reality.
> > 
> > This patch series makes HK_TYPE_KTHREAD an alias of HK_TYPE_DOMAIN
> > and uses RCU to protect access to the HK_TYPE_KTHREAD housekeeping
> > cpumask.
> > 
> > Waiman Long (2):
> >   sched/isolation: Make HK_TYPE_KTHREAD an alias of HK_TYPE_DOMAIN
> >   ipvs: Guard access of HK_TYPE_KTHREAD cpumask with RCU
> 
> 	The patchset looks good to me for nf-next, thanks!
> 
> Acked-by: Julian Anastasov <ja@ssi.bg>
> 
> 	Pablo, Florian, as a bugfix this patchset missed
> the chance to be applied before the changes that are in
> nf-next in ip_vs.h, there is little fuzz there. If there
> is no chance to resolve it somehow, we can apply it
> on top of nf-next where it now applies successfully.

One way to handle this is to follow up with nf-next as you suggest,
then send a backport that applies cleanly for -stable once it is
released.

Else, let me know if I am misunderstanding.

^ permalink raw reply

* [PATCH net-next] net: macb: Use netif_napi_add_tx() instead of netif_napi_add() for TX NAPI
From: Kevin Hao @ 2026-04-03 14:23 UTC (permalink / raw)
  To: Nicolas Ferre, Claudiu Beznea, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni
  Cc: netdev, Kevin Hao

The TX NAPI should be registered via netif_napi_add_tx() to avoid
unnecessarily polluting the napi_hash table.

Signed-off-by: Kevin Hao <haokexin@gmail.com>
---
 drivers/net/ethernet/cadence/macb_main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index 7f061d7c95af9aec37f73d3529a8cb276b263452..6a386e5632ac48a82414c370d58ae99f40fc3727 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -4770,7 +4770,7 @@ static int macb_init_dflt(struct platform_device *pdev)
 		queue->bp = bp;
 		spin_lock_init(&queue->tx_ptr_lock);
 		netif_napi_add(dev, &queue->napi_rx, macb_rx_poll);
-		netif_napi_add(dev, &queue->napi_tx, macb_tx_poll);
+		netif_napi_add_tx(dev, &queue->napi_tx, macb_tx_poll);
 		if (hw_q) {
 			queue->ISR  = GEM_ISR(hw_q - 1);
 			queue->IER  = GEM_IER(hw_q - 1);

---
base-commit: cc13002a9f984d37906e9476f3e532a8cdd126f5
change-id: 20260403-macb-napi-tx-7d5a8375d5d3

Best regards,
-- 
Kevin Hao <haokexin@gmail.com>


^ permalink raw reply related

* Re: [PATCH net v3] ipvs: fix MTU check for GSO packets in tunnel mode
From: Julian Anastasov @ 2026-04-03 14:20 UTC (permalink / raw)
  To: Yingnan Zhang
  Cc: horms, pablo, fw, phil, davem, edumazet, kuba, pabeni, netdev,
	lvs-devel, netfilter-devel, coreteam, linux-kernel
In-Reply-To: <tencent_73010FBD5FA1C05C3BC23A07A50B11CEC90A@qq.com>


	Hello,

On Thu, 2 Apr 2026, Yingnan Zhang wrote:

> Currently, IPVS skips MTU checks for GSO packets by excluding them with
> the !skb_is_gso(skb) condition. This creates problems when IPVS tunnel
> mode encapsulates GSO packets with IPIP headers.
> 
> The issue manifests in two ways:
> 
> 1. MTU violation after encapsulation:
>    When a GSO packet passes through IPVS tunnel mode, the original MTU
>    check is bypassed. After adding the IPIP tunnel header, the packet
>    size may exceed the outgoing interface MTU, leading to unexpected
>    fragmentation at the IP layer.
> 
> 2. Fragmentation with problematic IP IDs:
>    When net.ipv4.vs.pmtu_disc=1 and a GSO packet with multiple segments
>    is fragmented after encapsulation, each segment gets a sequentially
>    incremented IP ID (0, 1, 2, ...). This happens because:
> 
>    a) The GSO packet bypasses MTU check and gets encapsulated
>    b) At __ip_finish_output, the oversized GSO packet is split into
>       separate SKBs (one per segment), with IP IDs incrementing
>    c) Each SKB is then fragmented again based on the actual MTU
> 
>    This sequential IP ID allocation differs from the expected behavior
>    and can cause issues with fragment reassembly and packet tracking.
> 
> Fix this by properly validating GSO packets using
> skb_gso_validate_network_len(). This function correctly validates
> whether the GSO segments will fit within the MTU after segmentation. If
> validation fails, send an ICMP Fragmentation Needed message to enable
> proper PMTU discovery.
> 
> Fixes: 4cdd34084d53 ("netfilter: nf_conntrack_ipv6: improve fragmentation handling")
> Signed-off-by: Yingnan Zhang <342144303@qq.com>

	Looks good to me for the nf tree, thanks!

Acked-by: Julian Anastasov <ja@ssi.bg>

> ---
> v3:
> - Fixed compilation error (removed extra closing brace in IPv6 function)
> - Fixed indentation to match kernel style
> 
> v2: https://lore.kernel.org/netdev/20260402030541.27855-1-342144303@qq.com/
> v1: https://lore.kernel.org/netdev/20260401152228.31190-1-342144303@qq.com/
> ---
>  net/netfilter/ipvs/ip_vs_xmit.c | 9 +++++----
>  1 file changed, 5 insertions(+), 4 deletions(-)
> 
> diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
> index 3601eb86d..a4ca7cad0 100644
> --- a/net/netfilter/ipvs/ip_vs_xmit.c
> +++ b/net/netfilter/ipvs/ip_vs_xmit.c
> @@ -111,8 +111,8 @@ __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu)
>  		 */
>  		if (IP6CB(skb)->frag_max_size > mtu)
>  			return true; /* largest fragment violate MTU */
> -	}
> -	else if (skb->len > mtu && !skb_is_gso(skb)) {
> +	} else if (skb->len > mtu &&
> +		   !(skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu))) {
>  		return true; /* Packet size violate MTU size */
>  	}
>  	return false;
> @@ -232,8 +232,9 @@ static inline bool ensure_mtu_is_adequate(struct netns_ipvs *ipvs, int skb_af,
>  			return true;
>  
>  		if (unlikely(ip_hdr(skb)->frag_off & htons(IP_DF) &&
> -			     skb->len > mtu && !skb_is_gso(skb) &&
> -			     !ip_vs_iph_icmp(ipvsh))) {
> +			     skb->len > mtu && !ip_vs_iph_icmp(ipvsh) &&
> +			     !(skb_is_gso(skb) &&
> +			       skb_gso_validate_network_len(skb, mtu)))) {
>  			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
>  				  htonl(mtu));
>  			IP_VS_DBG(1, "frag needed for %pI4\n",
> -- 
> 2.51.0

Regards

--
Julian Anastasov <ja@ssi.bg>


^ permalink raw reply

* [PATCH net-next] selftests: forwarding: lib: rewrite processing of command line arguments
From: Ioana Ciornei @ 2026-04-03 14:19 UTC (permalink / raw)
  To: netdev
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, linux-kernel, petrm, willemb,
	linux-kselftest

The piece of code which processes the command line arguments and
populates NETIFS based on them is really unobvious. Rewrite it so that
the intention is clear and the code is easy to follow.

Suggested-by: Petr Machata <petrm@nvidia.com>
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
---
 tools/testing/selftests/net/forwarding/lib.sh | 22 +++++++++----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh
index d8cc4c64148d..922cdaf2ceb9 100644
--- a/tools/testing/selftests/net/forwarding/lib.sh
+++ b/tools/testing/selftests/net/forwarding/lib.sh
@@ -466,18 +466,18 @@ if [ "${DRIVER_TEST_CONFORMANT}" = "yes" ]; then
 	NETIFS[p2]="$remote_netif"
 	TARGETS[$remote_netif]="$REMOTE_TYPE:$REMOTE_ARGS"
 else
-	count=0
+	# Prime NETIFS from the command line, but retain if none given.
+	if [[ $# -gt 0 ]]; then
+		unset NETIFS
+		declare -A NETIFS
 
-	while [[ $# -gt 0 ]]; do
-		if [[ "$count" -eq "0" ]]; then
-			unset NETIFS
-			declare -A NETIFS
-		fi
-		count=$((count + 1))
-		NETIFS[p$count]="$1"
-		TARGETS[$1]="local:"
-		shift
-	done
+		while [[ $# -gt 0 ]]; do
+			count=$((count + 1))
+			NETIFS[p$count]="$1"
+			TARGETS[$1]="local:"
+			shift
+		done
+	fi
 fi
 
 ##############################################################################
-- 
2.25.1


^ permalink raw reply related

* Re: [PATCH net-next 4/5] mptcp: pm: in-kernel: remove mptcp_pm_has_addr_attr_id
From: Matthieu Baerts @ 2026-04-03 14:19 UTC (permalink / raw)
  To: Mat Martineau, Geliang Tang, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman
  Cc: netdev, mptcp, linux-kernel
In-Reply-To: <20260403-net-next-mptcp-msg_eor-misc-v1-4-b0b33bea3fed@kernel.org>

[-- Attachment #1: Type: text/plain, Size: 1279 bytes --]

Hello,

On 03/04/2026 13:29, Matthieu Baerts (NGI0) wrote:
> There is no need to call this helper: it will check if the address ID
> attribute is set, but this attribute has already been parsed previously.
> 
> Indeed, the value has been set in 'entry->addr.id' if it was set and
> positive, which is what we were looking at. Then only looking at this
> already parsed value is enough, not need to re-extract all Netlink
> attributes again.

Sashiko [1] is complaining that endpoints with an ID 0 are now no longer
supported. But they were never supposed to: "ip mptcp endpoint add id 0"
reports an error.

In fact, this patch is for 'net': from what I see, this patch reverts
commit 584f38942626 ("mptcp: add needs_id for netlink appending addr"),
which should not have been introduced. Other tools could happily add
endpoints with an unexpected ID 0.

If that's OK with the net maintainers, I suggest dropping only this
patch: the rest of the series is OK and not related to it. I will send
this exact same patch for 'net' after having adapted the commit message
and added a "Fixes" tag.

[1]
https://sashiko.dev/#/patchset/20260403-net-next-mptcp-msg_eor-misc-v1-0-b0b33bea3fed%40kernel.org

Cheers,
Matt
-- 
Sponsored by the NGI0 Core fund.


^ permalink raw reply

* Re: [PATCH net-next v2 3/4] net: dsa: yt921x: Add port police support
From: Andrew Lunn @ 2026-04-03 14:19 UTC (permalink / raw)
  To: David Yang
  Cc: netdev, Vladimir Oltean, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, linux-kernel
In-Reply-To: <CAAXyoMP=o7P0-o6HOKi8dho8iLLV4LJT=YHae5Gj13xJ2ph4og@mail.gmail.com>

> Does it unnecessarily depend on __int128? Otherwise it's good.

Ah, it seems to be a 64 bit architecture only thing.

Shame, because it would make this code easier to understand.

For these u96 values, the masks i looked at would fit into a u64.  Are
there any fields which cross from bits < 64 to > 64? Could you
represent it as a u64+u32?

	  Andrew

^ permalink raw reply

* Re: [PATCH-next v2 0/2] ipvs: Fix incorrect use of HK_TYPE_KTHREAD housekeeping cpumask
From: Julian Anastasov @ 2026-04-03 14:15 UTC (permalink / raw)
  To: Waiman Long
  Cc: Simon Horman, David S. Miller, David Ahern, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Pablo Neira Ayuso, Florian Westphal,
	Phil Sutter, Frederic Weisbecker, Chen Ridong, Phil Auld,
	linux-kernel, netdev, lvs-devel, netfilter-devel, coreteam,
	sheviks
In-Reply-To: <20260331165015.2777765-1-longman@redhat.com>


	Hello,

On Tue, 31 Mar 2026, Waiman Long wrote:

>  v2:
>   - Rebased on top of linux-next
> 
> Since commit 041ee6f3727a ("kthread: Rely on HK_TYPE_DOMAIN for preferred
> affinity management"), the HK_TYPE_KTHREAD housekeeping cpumask may no
> longer be correct in showing the actual CPU affinity of kthreads that
> have no predefined CPU affinity. As the ipvs networking code is still
> using HK_TYPE_KTHREAD, we need to make HK_TYPE_KTHREAD reflect the
> reality.
> 
> This patch series makes HK_TYPE_KTHREAD an alias of HK_TYPE_DOMAIN
> and uses RCU to protect access to the HK_TYPE_KTHREAD housekeeping
> cpumask.
> 
> Waiman Long (2):
>   sched/isolation: Make HK_TYPE_KTHREAD an alias of HK_TYPE_DOMAIN
>   ipvs: Guard access of HK_TYPE_KTHREAD cpumask with RCU

	The patchset looks good to me for nf-next, thanks!

Acked-by: Julian Anastasov <ja@ssi.bg>

	Pablo, Florian, as a bugfix this patchset missed
the chance to be applied before the changes that are in
nf-next in ip_vs.h, there is little fuzz there. If there
is no chance to resolve it somehow, we can apply it
on top of nf-next where it now applies successfully.

> 
>  include/linux/sched/isolation.h |  6 +++++-
>  include/net/ip_vs.h             | 20 ++++++++++++++++----
>  net/netfilter/ipvs/ip_vs_ctl.c  | 13 ++++++++-----
>  3 files changed, 29 insertions(+), 10 deletions(-)

Regards

--
Julian Anastasov <ja@ssi.bg>


^ permalink raw reply

* Re: [PATCH iproute2-next] ss: add support for TCP delack timers
From: Neal Cardwell @ 2026-04-03 14:14 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: David Ahern, Stephen Hemminger, David S . Miller, Jakub Kicinski,
	Paolo Abeni, Kuniyuki Iwashima, netdev, eric.dumazet
In-Reply-To: <20260403102309.338648-1-edumazet@google.com>

On Fri, Apr 3, 2026 at 5:23 AM Eric Dumazet <edumazet@google.com> wrote:
>
> Kernel commit c698f5cc940d ("inet_diag: report delayed ack timer information")
> added a new enum for idiag_timer values and support for delayed ack timers.
>
> Change tcp_timer_print() to use the new enum and display "delack"
> instead of "unknown":
>
> tt -to
> ...
>    ESTAB 10     0   [2002:a05:6830:1f86::]:12875 [2002:a05:6830:1f85::]:50438
>
>         timer:(delack,003ms,0) ino:152178 sk:3004 cgroup:unreachable:189 <->
>
>         skmem:(r1344,rb12780520,t0,tb262144,f2752,w0,o250,bl0,d0) ts usec_ts
>         ...
>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> ---

Reviewed-by: Neal Cardwell <ncardwell@google.com>

Thanks, Eric!

neal

^ permalink raw reply

* [PATCH net] net/sched: cls_fw: fix NULL dereference of "old" filters before change()
From: Davide Caratti @ 2026-04-03 14:13 UTC (permalink / raw)
  To: Jamal Hadi Salim, Jiri Pirko, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, Xiang Mei, netdev
  Cc: Victor Nogueira

Like pointed out by Sachiko [1], TC filters are added to a shared block
before their ->change() function is called. This is a problem for cls_fw:
an invalid filter created with the "old" method can still classify some
packets before it is destroyed by the validation logic added by Xiang.

Therefore, insisting with repeated runs of the following script:

 # ip link add dev crash0 type dummy
 # ip link set dev crash0 up
 # mausezahn  crash0 -c 100000 -P 10 \
 > -A 4.3.2.1 -B 1.2.3.4 -t udp "dp=1234" -q &
 # sleep 1
 #  tc qdisc add dev crash0 egress_block 1 clsact
 # tc filter add block 1 protocol ip prio 1 matchall \
 > action skbedit mark 65536 continue
 #  tc filter add block 1 protocol ip prio 2 fw
 # ip link del dev crash0

can still make fw_classify() hit the WARN_ON() in [2]:

 WARNING: ./include/net/pkt_cls.h:88 at fw_classify+0x244/0x250 [cls_fw], CPU#18: mausezahn/1399
 Modules linked in: cls_fw(E) act_skbedit(E)
 CPU: 18 UID: 0 PID: 1399 Comm: mausezahn Tainted: G            E       7.0.0-rc6-virtme #17 PREEMPT(full)
 Tainted: [E]=UNSIGNED_MODULE
 Hardware name: Red Hat KVM, BIOS 1.16.3-2.el9 04/01/2014
 RIP: 0010:fw_classify+0x244/0x250 [cls_fw]
 Code: 5c 49 c7 45 00 00 00 00 00 41 5d 41 5e 41 5f 5d c3 cc cc cc cc 5b b8 ff ff ff ff 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc 90 <0f> 0b 90 eb a0 0f 1f 80 00 00 00 00 90 90 90 90 90 90 90 90 90 90
 RSP: 0018:ffffd1b7026bf8a8 EFLAGS: 00010202
 RAX: ffff8c5ac9c60800 RBX: ffff8c5ac99322c0 RCX: 0000000000000004
 RDX: 0000000000000001 RSI: ffff8c5b74d7a000 RDI: ffff8c5ac8284f40
 RBP: ffffd1b7026bf8d0 R08: 0000000000000000 R09: ffffd1b7026bf9b0
 R10: 00000000ffffffff R11: 0000000000000000 R12: 0000000000010000
 R13: ffffd1b7026bf930 R14: ffff8c5ac8284f40 R15: 0000000000000000
 FS:  00007fca40c37740(0000) GS:ffff8c5b74d7a000(0000) knlGS:0000000000000000
 CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
 CR2: 00007fca40e822a0 CR3: 0000000005ca0001 CR4: 0000000000172ef0
 Call Trace:
  <TASK>
  tcf_classify+0x17d/0x5c0
  tc_run+0x9d/0x150
  __dev_queue_xmit+0x2ab/0x14d0
  ip_finish_output2+0x340/0x8f0
  ip_output+0xa4/0x250
  raw_sendmsg+0x147d/0x14b0
  __sys_sendto+0x1cc/0x1f0
  __x64_sys_sendto+0x24/0x30
  do_syscall_64+0x126/0xf80
  entry_SYSCALL_64_after_hwframe+0x77/0x7f
 RIP: 0033:0x7fca40e822ba
 Code: d8 64 89 02 48 c7 c0 ff ff ff ff eb b8 0f 1f 00 f3 0f 1e fa 41 89 ca 64 8b 04 25 18 00 00 00 85 c0 75 15 b8 2c 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 7e c3 0f 1f 44 00 00 41 54 48 83 ec 30 44 89
 RSP: 002b:00007ffc248a42c8 EFLAGS: 00000246 ORIG_RAX: 000000000000002c
 RAX: ffffffffffffffda RBX: 000055ef233289d0 RCX: 00007fca40e822ba
 RDX: 000000000000001e RSI: 000055ef23328c30 RDI: 0000000000000003
 RBP: 000055ef233289d0 R08: 00007ffc248a42d0 R09: 0000000000000010
 R10: 0000000000000000 R11: 0000000000000246 R12: 000000000000001e
 R13: 00000000000186a0 R14: 0000000000000000 R15: 00007fca41043000
  </TASK>
 irq event stamp: 1045778
 hardirqs last  enabled at (1045784): [<ffffffff864ec042>] __up_console_sem+0x52/0x60
 hardirqs last disabled at (1045789): [<ffffffff864ec027>] __up_console_sem+0x37/0x60
 softirqs last  enabled at (1045426): [<ffffffff874d48c7>] __alloc_skb+0x207/0x260
 softirqs last disabled at (1045434): [<ffffffff874fe8f8>] __dev_queue_xmit+0x78/0x14d0

Then, because of the value in the packet's mark, dereference on 'q->handle'
with NULL 'q' occurs:

 BUG: kernel NULL  pointer dereference, address: 0000000000000038
 [...]
 RIP: 0010:fw_classify+0x1fe/0x250 [cls_fw]
 [...]

Add a NULL check on 'q' to prevent the kernel from crashing. The WARN_ON()
is preserved to allow users fixing their configuration.

[1] https://sashiko.dev/#/patchset/20260331050217.504278-1-xmei5%40asu.edu
[2] https://elixir.bootlin.com/linux/v7.0-rc6/source/include/net/pkt_cls.h#L86

Fixes: faeea8bbf6e9 ("net/sched: cls_fw: fix NULL pointer dereference on shared blocks")
Signed-off-by: Davide Caratti <dcaratti@redhat.com>
---
 net/sched/cls_fw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
index 23884ef8b80c..10f46999ad2a 100644
--- a/net/sched/cls_fw.c
+++ b/net/sched/cls_fw.c
@@ -78,7 +78,7 @@ TC_INDIRECT_SCOPE int fw_classify(struct sk_buff *skb,
 
 		/* Old method: classify the packet using its skb mark. */
 		if (id && (TC_H_MAJ(id) == 0 ||
-			   !(TC_H_MAJ(id ^ q->handle)))) {
+			   (q && !(TC_H_MAJ(id ^ q->handle))))) {
 			res->classid = id;
 			res->class = 0;
 			return 0;
-- 
2.52.0


^ permalink raw reply related

* [PATCH 6/7] clk: qcom: gcc: Add multiple global clock controller driver for Nord SoC
From: Bartosz Golaszewski @ 2026-04-03 14:10 UTC (permalink / raw)
  To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Taniya Das, Taniya Das,
	Richard Cochran, Shawn Guo, Deepti Jaggi
  Cc: linux-arm-msm, linux-clk, devicetree, linux-kernel, netdev,
	Bartosz Golaszewski
In-Reply-To: <20260403-nord-clks-v1-0-018af14979fd@oss.qualcomm.com>

From: Taniya Das <taniya.das@oss.qualcomm.com>

The global clock controller on the Nord SoC is partitioned into
GCC, SE_GCC, NE_GCC, and NW_GCC. Introduce driver support for each
of these controllers.

Signed-off-by: Taniya Das <taniya.das@oss.qualcomm.com>
[Shawn: Drop include of <linux/of.h> as the driver doesn't use any OF APIs]
Co-developed-by: Shawn Guo <shengchao.guo@oss.qualcomm.com>
Signed-off-by: Shawn Guo <shengchao.guo@oss.qualcomm.com>
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
 drivers/clk/qcom/Kconfig      |   10 +
 drivers/clk/qcom/Makefile     |    1 +
 drivers/clk/qcom/gcc-nord.c   | 1901 +++++++++++++++++++++++++++++++++++++++
 drivers/clk/qcom/negcc-nord.c | 1987 +++++++++++++++++++++++++++++++++++++++++
 drivers/clk/qcom/nwgcc-nord.c |  688 ++++++++++++++
 drivers/clk/qcom/segcc-nord.c | 1609 +++++++++++++++++++++++++++++++++
 6 files changed, 6196 insertions(+)

diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 10c74db7e072f560f4bc26f81b4378034d1f9bf6..87efdf67124b3e1c2b6c5b976ef404aaa2ab5c23 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -145,6 +145,16 @@ config CLK_KAANAPALI_VIDEOCC
 	  Say Y if you want to support video devices and functionality such as
 	  video encode/decode.
 
+config CLK_NORD_GCC
+	tristate "Nord Global Clock Controller"
+	depends on ARM64 || COMPILE_TEST
+	select QCOM_GDSC
+	help
+	  Support for the global clock controller on Nord devices.
+	  Say Y if you want to use peripheral devices such as UART,
+	  SPI, I2C, USB, SD/UFS, PCIe etc. The clock controller is a combination
+	  of GCC, SE_GCC, NE_GCC and NW_GCC.
+
 config CLK_X1E80100_CAMCC
 	tristate "X1E80100 Camera Clock Controller"
 	depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 1a7ff1986b834f48dbaa2fd8c2559f0046ea7579..397261e9e387b4a1612296822076c1c001787ad7 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_CLK_KAANAPALI_GCC) += gcc-kaanapali.o
 obj-$(CONFIG_CLK_KAANAPALI_GPUCC) += gpucc-kaanapali.o gxclkctl-kaanapali.o
 obj-$(CONFIG_CLK_KAANAPALI_TCSRCC) += tcsrcc-kaanapali.o
 obj-$(CONFIG_CLK_KAANAPALI_VIDEOCC) += videocc-kaanapali.o
+obj-$(CONFIG_CLK_NORD_GCC) += gcc-nord.o negcc-nord.o nwgcc-nord.o segcc-nord.o
 obj-$(CONFIG_CLK_NORD_TCSRCC) += tcsrcc-nord.o
 obj-$(CONFIG_CLK_X1E80100_CAMCC) += camcc-x1e80100.o
 obj-$(CONFIG_CLK_X1E80100_DISPCC) += dispcc-x1e80100.o
diff --git a/drivers/clk/qcom/gcc-nord.c b/drivers/clk/qcom/gcc-nord.c
new file mode 100644
index 0000000000000000000000000000000000000000..ab24ebeadbdd23b2094d915bd8a8c83ae91e0e4f
--- /dev/null
+++ b/drivers/clk/qcom/gcc-nord.c
@@ -0,0 +1,1901 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,nord-gcc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+#include "clk-regmap-phy-mux.h"
+#include "common.h"
+#include "gdsc.h"
+#include "reset.h"
+
+enum {
+	DT_BI_TCXO,
+	DT_SLEEP_CLK,
+	DT_PCIE_A_PIPE_CLK,
+	DT_PCIE_B_PIPE_CLK,
+	DT_PCIE_C_PIPE_CLK,
+	DT_PCIE_D_PIPE_CLK,
+};
+
+enum {
+	P_BI_TCXO,
+	P_GCC_GPLL0_OUT_EVEN,
+	P_GCC_GPLL0_OUT_MAIN,
+	P_PCIE_A_PIPE_CLK,
+	P_PCIE_B_PIPE_CLK,
+	P_PCIE_C_PIPE_CLK,
+	P_PCIE_D_PIPE_CLK,
+	P_SLEEP_CLK,
+};
+
+static struct clk_alpha_pll gcc_gpll0 = {
+	.offset = 0x0,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+	.clkr = {
+		.enable_reg = 0x9d020,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_gpll0",
+			.parent_data = &(const struct clk_parent_data) {
+				.index = DT_BI_TCXO,
+			},
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+		},
+	},
+};
+
+static const struct clk_div_table post_div_table_gcc_gpll0_out_even[] = {
+	{ 0x1, 2 },
+	{ }
+};
+
+static struct clk_alpha_pll_postdiv gcc_gpll0_out_even = {
+	.offset = 0x0,
+	.post_div_shift = 10,
+	.post_div_table = post_div_table_gcc_gpll0_out_even,
+	.num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll0_out_even),
+	.width = 4,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "gcc_gpll0_out_even",
+		.parent_hws = (const struct clk_hw*[]) {
+			&gcc_gpll0.clkr.hw,
+		},
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+	},
+};
+
+static const struct parent_map gcc_parent_map_0[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_GCC_GPLL0_OUT_MAIN, 1 },
+	{ P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_0[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &gcc_gpll0.clkr.hw },
+	{ .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_1[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_SLEEP_CLK, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_1[] = {
+	{ .index = DT_BI_TCXO },
+	{ .index = DT_SLEEP_CLK },
+};
+
+static const struct parent_map gcc_parent_map_2[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_GCC_GPLL0_OUT_MAIN, 1 },
+	{ P_SLEEP_CLK, 5 },
+	{ P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_2[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &gcc_gpll0.clkr.hw },
+	{ .index = DT_SLEEP_CLK },
+	{ .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_3[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_GCC_GPLL0_OUT_MAIN, 1 },
+};
+
+static const struct clk_parent_data gcc_parent_data_3[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &gcc_gpll0.clkr.hw },
+};
+
+static struct clk_regmap_phy_mux gcc_pcie_a_pipe_clk_src = {
+	.reg = 0x49094,
+	.clkr = {
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_a_pipe_clk_src",
+			.parent_data = &(const struct clk_parent_data){
+				.index = DT_PCIE_A_PIPE_CLK,
+			},
+			.num_parents = 1,
+			.ops = &clk_regmap_phy_mux_ops,
+		},
+	},
+};
+
+static struct clk_regmap_phy_mux gcc_pcie_b_pipe_clk_src = {
+	.reg = 0x4a094,
+	.clkr = {
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_b_pipe_clk_src",
+			.parent_data = &(const struct clk_parent_data){
+				.index = DT_PCIE_B_PIPE_CLK,
+			},
+			.num_parents = 1,
+			.ops = &clk_regmap_phy_mux_ops,
+		},
+	},
+};
+
+static struct clk_regmap_phy_mux gcc_pcie_c_pipe_clk_src = {
+	.reg = 0x4b094,
+	.clkr = {
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_c_pipe_clk_src",
+			.parent_data = &(const struct clk_parent_data){
+				.index = DT_PCIE_C_PIPE_CLK,
+			},
+			.num_parents = 1,
+			.ops = &clk_regmap_phy_mux_ops,
+		},
+	},
+};
+
+static struct clk_regmap_phy_mux gcc_pcie_d_pipe_clk_src = {
+	.reg = 0x4c094,
+	.clkr = {
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_d_pipe_clk_src",
+			.parent_data = &(const struct clk_parent_data){
+				.index = DT_PCIE_D_PIPE_CLK,
+			},
+			.num_parents = 1,
+			.ops = &clk_regmap_phy_mux_ops,
+		},
+	},
+};
+
+static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = {
+	F(66666667, P_GCC_GPLL0_OUT_MAIN, 9, 0, 0),
+	F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+	F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 gcc_gp1_clk_src = {
+	.cmd_rcgr = 0x30004,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_2,
+	.freq_tbl = ftbl_gcc_gp1_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "gcc_gp1_clk_src",
+		.parent_data = gcc_parent_data_2,
+		.num_parents = ARRAY_SIZE(gcc_parent_data_2),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 gcc_gp2_clk_src = {
+	.cmd_rcgr = 0x31004,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_2,
+	.freq_tbl = ftbl_gcc_gp1_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "gcc_gp2_clk_src",
+		.parent_data = gcc_parent_data_2,
+		.num_parents = ARRAY_SIZE(gcc_parent_data_2),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_gcc_pcie_a_aux_clk_src[] = {
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 gcc_pcie_a_aux_clk_src = {
+	.cmd_rcgr = 0x49098,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_1,
+	.freq_tbl = ftbl_gcc_pcie_a_aux_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "gcc_pcie_a_aux_clk_src",
+		.parent_data = gcc_parent_data_1,
+		.num_parents = ARRAY_SIZE(gcc_parent_data_1),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 gcc_pcie_a_phy_aux_clk_src = {
+	.cmd_rcgr = 0x4d020,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_1,
+	.freq_tbl = ftbl_gcc_pcie_a_aux_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "gcc_pcie_a_phy_aux_clk_src",
+		.parent_data = gcc_parent_data_1,
+		.num_parents = ARRAY_SIZE(gcc_parent_data_1),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_gcc_pcie_a_phy_rchng_clk_src[] = {
+	F(66666667, P_GCC_GPLL0_OUT_MAIN, 9, 0, 0),
+	F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 gcc_pcie_a_phy_rchng_clk_src = {
+	.cmd_rcgr = 0x4907c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_0,
+	.freq_tbl = ftbl_gcc_pcie_a_phy_rchng_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "gcc_pcie_a_phy_rchng_clk_src",
+		.parent_data = gcc_parent_data_0,
+		.num_parents = ARRAY_SIZE(gcc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 gcc_pcie_b_aux_clk_src = {
+	.cmd_rcgr = 0x4a098,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_1,
+	.freq_tbl = ftbl_gcc_pcie_a_aux_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "gcc_pcie_b_aux_clk_src",
+		.parent_data = gcc_parent_data_1,
+		.num_parents = ARRAY_SIZE(gcc_parent_data_1),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 gcc_pcie_b_phy_aux_clk_src = {
+	.cmd_rcgr = 0x4e020,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_1,
+	.freq_tbl = ftbl_gcc_pcie_a_aux_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "gcc_pcie_b_phy_aux_clk_src",
+		.parent_data = gcc_parent_data_1,
+		.num_parents = ARRAY_SIZE(gcc_parent_data_1),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 gcc_pcie_b_phy_rchng_clk_src = {
+	.cmd_rcgr = 0x4a07c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_0,
+	.freq_tbl = ftbl_gcc_pcie_a_phy_rchng_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "gcc_pcie_b_phy_rchng_clk_src",
+		.parent_data = gcc_parent_data_0,
+		.num_parents = ARRAY_SIZE(gcc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 gcc_pcie_c_aux_clk_src = {
+	.cmd_rcgr = 0x4b098,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_1,
+	.freq_tbl = ftbl_gcc_pcie_a_aux_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "gcc_pcie_c_aux_clk_src",
+		.parent_data = gcc_parent_data_1,
+		.num_parents = ARRAY_SIZE(gcc_parent_data_1),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 gcc_pcie_c_phy_aux_clk_src = {
+	.cmd_rcgr = 0x4f020,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_1,
+	.freq_tbl = ftbl_gcc_pcie_a_aux_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "gcc_pcie_c_phy_aux_clk_src",
+		.parent_data = gcc_parent_data_1,
+		.num_parents = ARRAY_SIZE(gcc_parent_data_1),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 gcc_pcie_c_phy_rchng_clk_src = {
+	.cmd_rcgr = 0x4b07c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_3,
+	.freq_tbl = ftbl_gcc_pcie_a_phy_rchng_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "gcc_pcie_c_phy_rchng_clk_src",
+		.parent_data = gcc_parent_data_3,
+		.num_parents = ARRAY_SIZE(gcc_parent_data_3),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 gcc_pcie_d_aux_clk_src = {
+	.cmd_rcgr = 0x4c098,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_1,
+	.freq_tbl = ftbl_gcc_pcie_a_aux_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "gcc_pcie_d_aux_clk_src",
+		.parent_data = gcc_parent_data_1,
+		.num_parents = ARRAY_SIZE(gcc_parent_data_1),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 gcc_pcie_d_phy_aux_clk_src = {
+	.cmd_rcgr = 0x50020,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_1,
+	.freq_tbl = ftbl_gcc_pcie_a_aux_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "gcc_pcie_d_phy_aux_clk_src",
+		.parent_data = gcc_parent_data_1,
+		.num_parents = ARRAY_SIZE(gcc_parent_data_1),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 gcc_pcie_d_phy_rchng_clk_src = {
+	.cmd_rcgr = 0x4c07c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_3,
+	.freq_tbl = ftbl_gcc_pcie_a_phy_rchng_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "gcc_pcie_d_phy_rchng_clk_src",
+		.parent_data = gcc_parent_data_3,
+		.num_parents = ARRAY_SIZE(gcc_parent_data_3),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 gcc_pcie_noc_refgen_clk_src = {
+	.cmd_rcgr = 0x52094,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_0,
+	.freq_tbl = ftbl_gcc_pcie_a_aux_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "gcc_pcie_noc_refgen_clk_src",
+		.parent_data = gcc_parent_data_0,
+		.num_parents = ARRAY_SIZE(gcc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 gcc_pcie_noc_safety_clk_src = {
+	.cmd_rcgr = 0x520ac,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_0,
+	.freq_tbl = ftbl_gcc_pcie_a_aux_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "gcc_pcie_noc_safety_clk_src",
+		.parent_data = gcc_parent_data_0,
+		.num_parents = ARRAY_SIZE(gcc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = {
+	F(40000000, P_GCC_GPLL0_OUT_MAIN, 15, 0, 0),
+	F(60000000, P_GCC_GPLL0_OUT_MAIN, 10, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 gcc_pdm2_clk_src = {
+	.cmd_rcgr = 0x1a010,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_0,
+	.freq_tbl = ftbl_gcc_pdm2_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "gcc_pdm2_clk_src",
+		.parent_data = gcc_parent_data_0,
+		.num_parents = ARRAY_SIZE(gcc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap3_qspi_ref_clk_src[] = {
+	F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625),
+	F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625),
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625),
+	F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75),
+	F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25),
+	F(51200000, P_GCC_GPLL0_OUT_EVEN, 1, 64, 375),
+	F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75),
+	F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+	F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15),
+	F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25),
+	F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+	F(102400000, P_GCC_GPLL0_OUT_EVEN, 1, 128, 375),
+	F(112000000, P_GCC_GPLL0_OUT_EVEN, 1, 28, 75),
+	F(117964800, P_GCC_GPLL0_OUT_EVEN, 1, 6144, 15625),
+	F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0),
+	F(150000000, P_GCC_GPLL0_OUT_EVEN, 2, 0, 0),
+	F(240000000, P_GCC_GPLL0_OUT_MAIN, 2.5, 0, 0),
+	{ }
+};
+
+static struct clk_init_data gcc_qupv3_wrap3_qspi_ref_clk_src_init = {
+	.name = "gcc_qupv3_wrap3_qspi_ref_clk_src",
+	.parent_data = gcc_parent_data_0,
+	.num_parents = ARRAY_SIZE(gcc_parent_data_0),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap3_qspi_ref_clk_src = {
+	.cmd_rcgr = 0x23174,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = gcc_parent_map_0,
+	.freq_tbl = ftbl_gcc_qupv3_wrap3_qspi_ref_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &gcc_qupv3_wrap3_qspi_ref_clk_src_init,
+};
+
+static struct clk_regmap_div gcc_qupv3_wrap3_s0_clk_src = {
+	.reg = 0x2316c,
+	.shift = 0,
+	.width = 4,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "gcc_qupv3_wrap3_s0_clk_src",
+		.parent_hws = (const struct clk_hw*[]) {
+			&gcc_qupv3_wrap3_qspi_ref_clk_src.clkr.hw,
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_regmap_div_ro_ops,
+	},
+};
+
+static struct clk_branch gcc_boot_rom_ahb_clk = {
+	.halt_reg = 0x1f004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1f004,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_boot_rom_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gp1_clk = {
+	.halt_reg = 0x30000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x30000,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_gp1_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_gp1_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_gp2_clk = {
+	.halt_reg = 0x31000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x31000,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_gp2_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_gp2_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_mmu_0_tcu_vote_clk = {
+	.halt_reg = 0x7d094,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x7d094,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_mmu_0_tcu_vote_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_a_aux_clk = {
+	.halt_reg = 0x49058,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x49058,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(14),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_a_aux_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_pcie_a_aux_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_a_cfg_ahb_clk = {
+	.halt_reg = 0x49054,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x49054,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(13),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_a_cfg_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_a_dti_qtc_clk = {
+	.halt_reg = 0x49018,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x49018,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(8),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_a_dti_qtc_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_a_mstr_axi_clk = {
+	.halt_reg = 0x49040,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x49040,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(12),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_a_mstr_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_a_phy_aux_clk = {
+	.halt_reg = 0x4d01c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(12),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_a_phy_aux_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_pcie_a_phy_aux_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_a_phy_rchng_clk = {
+	.halt_reg = 0x49078,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x49078,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(16),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_a_phy_rchng_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_pcie_a_phy_rchng_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_a_pipe_clk = {
+	.halt_reg = 0x49068,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x49068,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(15),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_a_pipe_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_pcie_a_pipe_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_a_slv_axi_clk = {
+	.halt_reg = 0x4902c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x4902c,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(11),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_a_slv_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_a_slv_q2a_axi_clk = {
+	.halt_reg = 0x49024,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x49024,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(10),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_a_slv_q2a_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_b_aux_clk = {
+	.halt_reg = 0x4a058,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(23),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_b_aux_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_pcie_b_aux_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_b_cfg_ahb_clk = {
+	.halt_reg = 0x4a054,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x4a054,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(22),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_b_cfg_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_b_dti_qtc_clk = {
+	.halt_reg = 0x4a018,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x4a018,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(17),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_b_dti_qtc_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_b_mstr_axi_clk = {
+	.halt_reg = 0x4a040,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x4a040,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(21),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_b_mstr_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_b_phy_aux_clk = {
+	.halt_reg = 0x4e01c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(13),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_b_phy_aux_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_pcie_b_phy_aux_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_b_phy_rchng_clk = {
+	.halt_reg = 0x4a078,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(25),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_b_phy_rchng_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_pcie_b_phy_rchng_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_b_pipe_clk = {
+	.halt_reg = 0x4a068,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(24),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_b_pipe_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_pcie_b_pipe_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_b_slv_axi_clk = {
+	.halt_reg = 0x4a02c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x4a02c,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(20),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_b_slv_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_b_slv_q2a_axi_clk = {
+	.halt_reg = 0x4a024,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(19),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_b_slv_q2a_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_c_aux_clk = {
+	.halt_reg = 0x4b058,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_c_aux_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_pcie_c_aux_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_c_cfg_ahb_clk = {
+	.halt_reg = 0x4b054,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x4b054,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(31),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_c_cfg_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_c_dti_qtc_clk = {
+	.halt_reg = 0x4b018,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x4b018,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(26),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_c_dti_qtc_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_c_mstr_axi_clk = {
+	.halt_reg = 0x4b040,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x4b040,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(30),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_c_mstr_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_c_phy_aux_clk = {
+	.halt_reg = 0x4f01c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(14),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_c_phy_aux_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_pcie_c_phy_aux_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_c_phy_rchng_clk = {
+	.halt_reg = 0x4b078,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(2),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_c_phy_rchng_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_pcie_c_phy_rchng_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_c_pipe_clk = {
+	.halt_reg = 0x4b068,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(1),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_c_pipe_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_pcie_c_pipe_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_c_slv_axi_clk = {
+	.halt_reg = 0x4b02c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x4b02c,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(29),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_c_slv_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_c_slv_q2a_axi_clk = {
+	.halt_reg = 0x4b024,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d008,
+		.enable_mask = BIT(28),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_c_slv_q2a_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_d_aux_clk = {
+	.halt_reg = 0x4c058,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(9),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_d_aux_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_pcie_d_aux_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_d_cfg_ahb_clk = {
+	.halt_reg = 0x4c054,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x4c054,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(8),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_d_cfg_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_d_dti_qtc_clk = {
+	.halt_reg = 0x4c018,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x4c018,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(3),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_d_dti_qtc_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_d_mstr_axi_clk = {
+	.halt_reg = 0x4c040,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x4c040,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(7),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_d_mstr_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_d_phy_aux_clk = {
+	.halt_reg = 0x5001c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(16),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_d_phy_aux_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_pcie_d_phy_aux_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_d_phy_rchng_clk = {
+	.halt_reg = 0x4c078,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(11),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_d_phy_rchng_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_pcie_d_phy_rchng_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_d_pipe_clk = {
+	.halt_reg = 0x4c068,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(10),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_d_pipe_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_pcie_d_pipe_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_d_slv_axi_clk = {
+	.halt_reg = 0x4c02c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x4c02c,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(6),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_d_slv_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_d_slv_q2a_axi_clk = {
+	.halt_reg = 0x4c024,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(5),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_d_slv_q2a_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_link_ahb_clk = {
+	.halt_reg = 0x52464,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x52464,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_link_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_link_xo_clk = {
+	.halt_reg = 0x52468,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x52468,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x52468,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_link_xo_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_noc_async_bridge_clk = {
+	.halt_reg = 0x52048,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x52048,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d018,
+		.enable_mask = BIT(18),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_noc_async_bridge_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_noc_cnoc_sf_qx_clk = {
+	.halt_reg = 0x52040,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x52040,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(24),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_noc_cnoc_sf_qx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_noc_m_cfg_clk = {
+	.halt_reg = 0x52060,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x52060,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d018,
+		.enable_mask = BIT(4),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_noc_m_cfg_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_noc_m_pdb_clk = {
+	.halt_reg = 0x52084,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x52084,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d018,
+		.enable_mask = BIT(8),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_noc_m_pdb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_noc_mstr_axi_clk = {
+	.halt_reg = 0x52050,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x52050,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(25),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_noc_mstr_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_noc_pwrctl_clk = {
+	.halt_reg = 0x52080,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d018,
+		.enable_mask = BIT(7),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_noc_pwrctl_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_noc_qosgen_extref_clk = {
+	.halt_reg = 0x52074,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(19),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_noc_qosgen_extref_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_noc_refgen_clk = {
+	.halt_reg = 0x52078,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x52078,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_noc_refgen_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_pcie_noc_refgen_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_noc_s_cfg_clk = {
+	.halt_reg = 0x52064,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d018,
+		.enable_mask = BIT(5),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_noc_s_cfg_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_noc_s_pdb_clk = {
+	.halt_reg = 0x5208c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x5208c,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d018,
+		.enable_mask = BIT(9),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_noc_s_pdb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_noc_safety_clk = {
+	.halt_reg = 0x5207c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x5207c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_noc_safety_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_pcie_noc_safety_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_noc_slave_axi_clk = {
+	.halt_reg = 0x52058,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x52058,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(26),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_noc_slave_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_noc_tsctr_clk = {
+	.halt_reg = 0x52070,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(18),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_noc_tsctr_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pcie_noc_xo_clk = {
+	.halt_reg = 0x52068,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d018,
+		.enable_mask = BIT(6),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pcie_noc_xo_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pdm2_clk = {
+	.halt_reg = 0x1a00c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1a00c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pdm2_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_pdm2_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pdm_ahb_clk = {
+	.halt_reg = 0x1a004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x1a004,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x1a004,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pdm_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_pdm_xo4_clk = {
+	.halt_reg = 0x1a008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1a008,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_pdm_xo4_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_qupv3_wrap3_core_2x_clk = {
+	.halt_reg = 0x23020,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d000,
+		.enable_mask = BIT(24),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_qupv3_wrap3_core_2x_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_qupv3_wrap3_core_clk = {
+	.halt_reg = 0x2300c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d000,
+		.enable_mask = BIT(23),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_qupv3_wrap3_core_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_qupv3_wrap3_m_clk = {
+	.halt_reg = 0x23004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x23004,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d000,
+		.enable_mask = BIT(22),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_qupv3_wrap3_m_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_qupv3_wrap3_qspi_ref_clk = {
+	.halt_reg = 0x23170,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d000,
+		.enable_mask = BIT(26),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_qupv3_wrap3_qspi_ref_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_qupv3_wrap3_qspi_ref_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_qupv3_wrap3_s0_clk = {
+	.halt_reg = 0x2315c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x9d000,
+		.enable_mask = BIT(25),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_qupv3_wrap3_s0_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&gcc_qupv3_wrap3_s0_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_qupv3_wrap3_s_ahb_clk = {
+	.halt_reg = 0x23008,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x23008,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x9d010,
+		.enable_mask = BIT(15),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_qupv3_wrap3_s_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch gcc_smmu_pcie_qtc_vote_clk = {
+	.halt_reg = 0x7d0b8,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x7d0b8,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "gcc_smmu_pcie_qtc_vote_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct gdsc gcc_pcie_a_gdsc = {
+	.gdscr = 0x49004,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0xf,
+	.collapse_ctrl = 0x8d02c,
+	.collapse_mask = BIT(1),
+	.pd = {
+		.name = "gcc_pcie_a_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_a_phy_gdsc = {
+	.gdscr = 0x4d004,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0x2,
+	.collapse_ctrl = 0x8d02c,
+	.collapse_mask = BIT(5),
+	.pd = {
+		.name = "gcc_pcie_a_phy_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_b_gdsc = {
+	.gdscr = 0x4a004,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0xf,
+	.collapse_ctrl = 0x8d02c,
+	.collapse_mask = BIT(2),
+	.pd = {
+		.name = "gcc_pcie_b_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_b_phy_gdsc = {
+	.gdscr = 0x4e004,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0x2,
+	.collapse_ctrl = 0x8d02c,
+	.collapse_mask = BIT(6),
+	.pd = {
+		.name = "gcc_pcie_b_phy_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_c_gdsc = {
+	.gdscr = 0x4b004,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0xf,
+	.collapse_ctrl = 0x8d02c,
+	.collapse_mask = BIT(3),
+	.pd = {
+		.name = "gcc_pcie_c_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_c_phy_gdsc = {
+	.gdscr = 0x4f004,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0x2,
+	.collapse_ctrl = 0x8d02c,
+	.collapse_mask = BIT(7),
+	.pd = {
+		.name = "gcc_pcie_c_phy_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_d_gdsc = {
+	.gdscr = 0x4c004,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0xf,
+	.collapse_ctrl = 0x8d02c,
+	.collapse_mask = BIT(4),
+	.pd = {
+		.name = "gcc_pcie_d_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_d_phy_gdsc = {
+	.gdscr = 0x50004,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0x2,
+	.collapse_ctrl = 0x8d02c,
+	.collapse_mask = BIT(8),
+	.pd = {
+		.name = "gcc_pcie_d_phy_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_noc_gdsc = {
+	.gdscr = 0x52004,
+	.gds_hw_ctrl = 0x52018,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0xf,
+	.collapse_ctrl = 0x8d02c,
+	.collapse_mask = BIT(0),
+	.pd = {
+		.name = "gcc_pcie_noc_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct clk_regmap *gcc_nord_clocks[] = {
+	[GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
+	[GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
+	[GCC_GP1_CLK_SRC] = &gcc_gp1_clk_src.clkr,
+	[GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
+	[GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr,
+	[GCC_GPLL0] = &gcc_gpll0.clkr,
+	[GCC_GPLL0_OUT_EVEN] = &gcc_gpll0_out_even.clkr,
+	[GCC_MMU_0_TCU_VOTE_CLK] = &gcc_mmu_0_tcu_vote_clk.clkr,
+	[GCC_PCIE_A_AUX_CLK] = &gcc_pcie_a_aux_clk.clkr,
+	[GCC_PCIE_A_AUX_CLK_SRC] = &gcc_pcie_a_aux_clk_src.clkr,
+	[GCC_PCIE_A_CFG_AHB_CLK] = &gcc_pcie_a_cfg_ahb_clk.clkr,
+	[GCC_PCIE_A_DTI_QTC_CLK] = &gcc_pcie_a_dti_qtc_clk.clkr,
+	[GCC_PCIE_A_MSTR_AXI_CLK] = &gcc_pcie_a_mstr_axi_clk.clkr,
+	[GCC_PCIE_A_PHY_AUX_CLK] = &gcc_pcie_a_phy_aux_clk.clkr,
+	[GCC_PCIE_A_PHY_AUX_CLK_SRC] = &gcc_pcie_a_phy_aux_clk_src.clkr,
+	[GCC_PCIE_A_PHY_RCHNG_CLK] = &gcc_pcie_a_phy_rchng_clk.clkr,
+	[GCC_PCIE_A_PHY_RCHNG_CLK_SRC] = &gcc_pcie_a_phy_rchng_clk_src.clkr,
+	[GCC_PCIE_A_PIPE_CLK] = &gcc_pcie_a_pipe_clk.clkr,
+	[GCC_PCIE_A_PIPE_CLK_SRC] = &gcc_pcie_a_pipe_clk_src.clkr,
+	[GCC_PCIE_A_SLV_AXI_CLK] = &gcc_pcie_a_slv_axi_clk.clkr,
+	[GCC_PCIE_A_SLV_Q2A_AXI_CLK] = &gcc_pcie_a_slv_q2a_axi_clk.clkr,
+	[GCC_PCIE_B_AUX_CLK] = &gcc_pcie_b_aux_clk.clkr,
+	[GCC_PCIE_B_AUX_CLK_SRC] = &gcc_pcie_b_aux_clk_src.clkr,
+	[GCC_PCIE_B_CFG_AHB_CLK] = &gcc_pcie_b_cfg_ahb_clk.clkr,
+	[GCC_PCIE_B_DTI_QTC_CLK] = &gcc_pcie_b_dti_qtc_clk.clkr,
+	[GCC_PCIE_B_MSTR_AXI_CLK] = &gcc_pcie_b_mstr_axi_clk.clkr,
+	[GCC_PCIE_B_PHY_AUX_CLK] = &gcc_pcie_b_phy_aux_clk.clkr,
+	[GCC_PCIE_B_PHY_AUX_CLK_SRC] = &gcc_pcie_b_phy_aux_clk_src.clkr,
+	[GCC_PCIE_B_PHY_RCHNG_CLK] = &gcc_pcie_b_phy_rchng_clk.clkr,
+	[GCC_PCIE_B_PHY_RCHNG_CLK_SRC] = &gcc_pcie_b_phy_rchng_clk_src.clkr,
+	[GCC_PCIE_B_PIPE_CLK] = &gcc_pcie_b_pipe_clk.clkr,
+	[GCC_PCIE_B_PIPE_CLK_SRC] = &gcc_pcie_b_pipe_clk_src.clkr,
+	[GCC_PCIE_B_SLV_AXI_CLK] = &gcc_pcie_b_slv_axi_clk.clkr,
+	[GCC_PCIE_B_SLV_Q2A_AXI_CLK] = &gcc_pcie_b_slv_q2a_axi_clk.clkr,
+	[GCC_PCIE_C_AUX_CLK] = &gcc_pcie_c_aux_clk.clkr,
+	[GCC_PCIE_C_AUX_CLK_SRC] = &gcc_pcie_c_aux_clk_src.clkr,
+	[GCC_PCIE_C_CFG_AHB_CLK] = &gcc_pcie_c_cfg_ahb_clk.clkr,
+	[GCC_PCIE_C_DTI_QTC_CLK] = &gcc_pcie_c_dti_qtc_clk.clkr,
+	[GCC_PCIE_C_MSTR_AXI_CLK] = &gcc_pcie_c_mstr_axi_clk.clkr,
+	[GCC_PCIE_C_PHY_AUX_CLK] = &gcc_pcie_c_phy_aux_clk.clkr,
+	[GCC_PCIE_C_PHY_AUX_CLK_SRC] = &gcc_pcie_c_phy_aux_clk_src.clkr,
+	[GCC_PCIE_C_PHY_RCHNG_CLK] = &gcc_pcie_c_phy_rchng_clk.clkr,
+	[GCC_PCIE_C_PHY_RCHNG_CLK_SRC] = &gcc_pcie_c_phy_rchng_clk_src.clkr,
+	[GCC_PCIE_C_PIPE_CLK] = &gcc_pcie_c_pipe_clk.clkr,
+	[GCC_PCIE_C_PIPE_CLK_SRC] = &gcc_pcie_c_pipe_clk_src.clkr,
+	[GCC_PCIE_C_SLV_AXI_CLK] = &gcc_pcie_c_slv_axi_clk.clkr,
+	[GCC_PCIE_C_SLV_Q2A_AXI_CLK] = &gcc_pcie_c_slv_q2a_axi_clk.clkr,
+	[GCC_PCIE_D_AUX_CLK] = &gcc_pcie_d_aux_clk.clkr,
+	[GCC_PCIE_D_AUX_CLK_SRC] = &gcc_pcie_d_aux_clk_src.clkr,
+	[GCC_PCIE_D_CFG_AHB_CLK] = &gcc_pcie_d_cfg_ahb_clk.clkr,
+	[GCC_PCIE_D_DTI_QTC_CLK] = &gcc_pcie_d_dti_qtc_clk.clkr,
+	[GCC_PCIE_D_MSTR_AXI_CLK] = &gcc_pcie_d_mstr_axi_clk.clkr,
+	[GCC_PCIE_D_PHY_AUX_CLK] = &gcc_pcie_d_phy_aux_clk.clkr,
+	[GCC_PCIE_D_PHY_AUX_CLK_SRC] = &gcc_pcie_d_phy_aux_clk_src.clkr,
+	[GCC_PCIE_D_PHY_RCHNG_CLK] = &gcc_pcie_d_phy_rchng_clk.clkr,
+	[GCC_PCIE_D_PHY_RCHNG_CLK_SRC] = &gcc_pcie_d_phy_rchng_clk_src.clkr,
+	[GCC_PCIE_D_PIPE_CLK] = &gcc_pcie_d_pipe_clk.clkr,
+	[GCC_PCIE_D_PIPE_CLK_SRC] = &gcc_pcie_d_pipe_clk_src.clkr,
+	[GCC_PCIE_D_SLV_AXI_CLK] = &gcc_pcie_d_slv_axi_clk.clkr,
+	[GCC_PCIE_D_SLV_Q2A_AXI_CLK] = &gcc_pcie_d_slv_q2a_axi_clk.clkr,
+	[GCC_PCIE_LINK_AHB_CLK] = &gcc_pcie_link_ahb_clk.clkr,
+	[GCC_PCIE_LINK_XO_CLK] = &gcc_pcie_link_xo_clk.clkr,
+	[GCC_PCIE_NOC_ASYNC_BRIDGE_CLK] = &gcc_pcie_noc_async_bridge_clk.clkr,
+	[GCC_PCIE_NOC_CNOC_SF_QX_CLK] = &gcc_pcie_noc_cnoc_sf_qx_clk.clkr,
+	[GCC_PCIE_NOC_M_CFG_CLK] = &gcc_pcie_noc_m_cfg_clk.clkr,
+	[GCC_PCIE_NOC_M_PDB_CLK] = &gcc_pcie_noc_m_pdb_clk.clkr,
+	[GCC_PCIE_NOC_MSTR_AXI_CLK] = &gcc_pcie_noc_mstr_axi_clk.clkr,
+	[GCC_PCIE_NOC_PWRCTL_CLK] = &gcc_pcie_noc_pwrctl_clk.clkr,
+	[GCC_PCIE_NOC_QOSGEN_EXTREF_CLK] = &gcc_pcie_noc_qosgen_extref_clk.clkr,
+	[GCC_PCIE_NOC_REFGEN_CLK] = &gcc_pcie_noc_refgen_clk.clkr,
+	[GCC_PCIE_NOC_REFGEN_CLK_SRC] = &gcc_pcie_noc_refgen_clk_src.clkr,
+	[GCC_PCIE_NOC_S_CFG_CLK] = &gcc_pcie_noc_s_cfg_clk.clkr,
+	[GCC_PCIE_NOC_S_PDB_CLK] = &gcc_pcie_noc_s_pdb_clk.clkr,
+	[GCC_PCIE_NOC_SAFETY_CLK] = &gcc_pcie_noc_safety_clk.clkr,
+	[GCC_PCIE_NOC_SAFETY_CLK_SRC] = &gcc_pcie_noc_safety_clk_src.clkr,
+	[GCC_PCIE_NOC_SLAVE_AXI_CLK] = &gcc_pcie_noc_slave_axi_clk.clkr,
+	[GCC_PCIE_NOC_TSCTR_CLK] = &gcc_pcie_noc_tsctr_clk.clkr,
+	[GCC_PCIE_NOC_XO_CLK] = &gcc_pcie_noc_xo_clk.clkr,
+	[GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr,
+	[GCC_PDM2_CLK_SRC] = &gcc_pdm2_clk_src.clkr,
+	[GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr,
+	[GCC_PDM_XO4_CLK] = &gcc_pdm_xo4_clk.clkr,
+	[GCC_QUPV3_WRAP3_CORE_2X_CLK] = &gcc_qupv3_wrap3_core_2x_clk.clkr,
+	[GCC_QUPV3_WRAP3_CORE_CLK] = &gcc_qupv3_wrap3_core_clk.clkr,
+	[GCC_QUPV3_WRAP3_M_CLK] = &gcc_qupv3_wrap3_m_clk.clkr,
+	[GCC_QUPV3_WRAP3_QSPI_REF_CLK] = &gcc_qupv3_wrap3_qspi_ref_clk.clkr,
+	[GCC_QUPV3_WRAP3_QSPI_REF_CLK_SRC] = &gcc_qupv3_wrap3_qspi_ref_clk_src.clkr,
+	[GCC_QUPV3_WRAP3_S0_CLK] = &gcc_qupv3_wrap3_s0_clk.clkr,
+	[GCC_QUPV3_WRAP3_S0_CLK_SRC] = &gcc_qupv3_wrap3_s0_clk_src.clkr,
+	[GCC_QUPV3_WRAP3_S_AHB_CLK] = &gcc_qupv3_wrap3_s_ahb_clk.clkr,
+	[GCC_SMMU_PCIE_QTC_VOTE_CLK] = &gcc_smmu_pcie_qtc_vote_clk.clkr,
+};
+
+static struct gdsc *gcc_nord_gdscs[] = {
+	[GCC_PCIE_A_GDSC] = &gcc_pcie_a_gdsc,
+	[GCC_PCIE_A_PHY_GDSC] = &gcc_pcie_a_phy_gdsc,
+	[GCC_PCIE_B_GDSC] = &gcc_pcie_b_gdsc,
+	[GCC_PCIE_B_PHY_GDSC] = &gcc_pcie_b_phy_gdsc,
+	[GCC_PCIE_C_GDSC] = &gcc_pcie_c_gdsc,
+	[GCC_PCIE_C_PHY_GDSC] = &gcc_pcie_c_phy_gdsc,
+	[GCC_PCIE_D_GDSC] = &gcc_pcie_d_gdsc,
+	[GCC_PCIE_D_PHY_GDSC] = &gcc_pcie_d_phy_gdsc,
+	[GCC_PCIE_NOC_GDSC] = &gcc_pcie_noc_gdsc,
+};
+
+static const struct qcom_reset_map gcc_nord_resets[] = {
+	[GCC_PCIE_A_BCR] = { 0x49000 },
+	[GCC_PCIE_A_LINK_DOWN_BCR] = { 0xb9000 },
+	[GCC_PCIE_A_NOCSR_COM_PHY_BCR] = { 0xb900c },
+	[GCC_PCIE_A_PHY_BCR] = { 0x4d000 },
+	[GCC_PCIE_A_PHY_CFG_AHB_BCR] = { 0xb9014 },
+	[GCC_PCIE_A_PHY_COM_BCR] = { 0xb9018 },
+	[GCC_PCIE_A_PHY_NOCSR_COM_PHY_BCR] = { 0xb9010 },
+	[GCC_PCIE_B_BCR] = { 0x4a000 },
+	[GCC_PCIE_B_LINK_DOWN_BCR] = { 0xba000 },
+	[GCC_PCIE_B_NOCSR_COM_PHY_BCR] = { 0xba008 },
+	[GCC_PCIE_B_PHY_BCR] = { 0x4e000 },
+	[GCC_PCIE_B_PHY_CFG_AHB_BCR] = { 0xba010 },
+	[GCC_PCIE_B_PHY_COM_BCR] = { 0xba014 },
+	[GCC_PCIE_B_PHY_NOCSR_COM_PHY_BCR] = { 0xba00c },
+	[GCC_PCIE_C_BCR] = { 0x4b000 },
+	[GCC_PCIE_C_LINK_DOWN_BCR] = { 0xbb07c },
+	[GCC_PCIE_C_NOCSR_COM_PHY_BCR] = { 0xbb084 },
+	[GCC_PCIE_C_PHY_BCR] = { 0x4f000 },
+	[GCC_PCIE_C_PHY_CFG_AHB_BCR] = { 0xbb08c },
+	[GCC_PCIE_C_PHY_COM_BCR] = { 0xbb090 },
+	[GCC_PCIE_C_PHY_NOCSR_COM_PHY_BCR] = { 0xbb088 },
+	[GCC_PCIE_D_BCR] = { 0x4c000 },
+	[GCC_PCIE_D_LINK_DOWN_BCR] = { 0xbc000 },
+	[GCC_PCIE_D_NOCSR_COM_PHY_BCR] = { 0xbc008 },
+	[GCC_PCIE_D_PHY_BCR] = { 0x50000 },
+	[GCC_PCIE_D_PHY_CFG_AHB_BCR] = { 0xbc010 },
+	[GCC_PCIE_D_PHY_COM_BCR] = { 0xbc014 },
+	[GCC_PCIE_D_PHY_NOCSR_COM_PHY_BCR] = { 0xbc00c },
+	[GCC_PCIE_NOC_BCR] = { 0x52000 },
+	[GCC_PDM_BCR] = { 0x1a000 },
+	[GCC_QUPV3_WRAPPER_3_BCR] = { 0x23000 },
+	[GCC_TCSR_PCIE_BCR] = { 0xb901c },
+};
+
+static const struct clk_rcg_dfs_data gcc_nord_dfs_clocks[] = {
+	DEFINE_RCG_DFS(gcc_qupv3_wrap3_qspi_ref_clk_src),
+};
+
+static const struct regmap_config gcc_nord_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = 0x1f41f0,
+	.fast_io = true,
+};
+
+static struct qcom_cc_driver_data gcc_nord_driver_data = {
+	.dfs_rcgs = gcc_nord_dfs_clocks,
+	.num_dfs_rcgs = ARRAY_SIZE(gcc_nord_dfs_clocks),
+};
+
+static const struct qcom_cc_desc gcc_nord_desc = {
+	.config = &gcc_nord_regmap_config,
+	.clks = gcc_nord_clocks,
+	.num_clks = ARRAY_SIZE(gcc_nord_clocks),
+	.resets = gcc_nord_resets,
+	.num_resets = ARRAY_SIZE(gcc_nord_resets),
+	.gdscs = gcc_nord_gdscs,
+	.num_gdscs = ARRAY_SIZE(gcc_nord_gdscs),
+	.driver_data = &gcc_nord_driver_data,
+};
+
+static const struct of_device_id gcc_nord_match_table[] = {
+	{ .compatible = "qcom,nord-gcc" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, gcc_nord_match_table);
+
+static int gcc_nord_probe(struct platform_device *pdev)
+{
+	return qcom_cc_probe(pdev, &gcc_nord_desc);
+}
+
+static struct platform_driver gcc_nord_driver = {
+	.probe = gcc_nord_probe,
+	.driver = {
+		.name = "gcc-nord",
+		.of_match_table = gcc_nord_match_table,
+	},
+};
+
+static int __init gcc_nord_init(void)
+{
+	return platform_driver_register(&gcc_nord_driver);
+}
+subsys_initcall(gcc_nord_init);
+
+static void __exit gcc_nord_exit(void)
+{
+	platform_driver_unregister(&gcc_nord_driver);
+}
+module_exit(gcc_nord_exit);
+
+MODULE_DESCRIPTION("QTI GCC NORD Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/negcc-nord.c b/drivers/clk/qcom/negcc-nord.c
new file mode 100644
index 0000000000000000000000000000000000000000..1aa24e2784e536e6b6e76f488abd0e2fcc435380
--- /dev/null
+++ b/drivers/clk/qcom/negcc-nord.c
@@ -0,0 +1,1987 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,nord-negcc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+#include "clk-regmap-phy-mux.h"
+#include "common.h"
+#include "gdsc.h"
+#include "reset.h"
+
+enum {
+	DT_BI_TCXO,
+	DT_SLEEP_CLK,
+	DT_UFS_PHY_RX_SYMBOL_0_CLK,
+	DT_UFS_PHY_RX_SYMBOL_1_CLK,
+	DT_UFS_PHY_TX_SYMBOL_0_CLK,
+	DT_USB3_PHY_SEC_WRAPPER_NE_GCC_USB31_PIPE_CLK,
+	DT_USB3_PHY_WRAPPER_NE_GCC_USB31_PIPE_CLK,
+};
+
+enum {
+	P_BI_TCXO,
+	P_NE_GCC_GPLL0_OUT_EVEN,
+	P_NE_GCC_GPLL0_OUT_MAIN,
+	P_NE_GCC_GPLL2_OUT_MAIN,
+	P_SLEEP_CLK,
+	P_UFS_PHY_RX_SYMBOL_0_CLK,
+	P_UFS_PHY_RX_SYMBOL_1_CLK,
+	P_UFS_PHY_TX_SYMBOL_0_CLK,
+	P_USB3_PHY_SEC_WRAPPER_NE_GCC_USB31_PIPE_CLK,
+	P_USB3_PHY_WRAPPER_NE_GCC_USB31_PIPE_CLK,
+};
+
+static struct clk_alpha_pll ne_gcc_gpll0 = {
+	.offset = 0x0,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+	.clkr = {
+		.enable_reg = 0x0,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_gpll0",
+			.parent_data = &(const struct clk_parent_data) {
+				.index = DT_BI_TCXO,
+			},
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+		},
+	},
+};
+
+static const struct clk_div_table post_div_table_ne_gcc_gpll0_out_even[] = {
+	{ 0x1, 2 },
+	{ }
+};
+
+static struct clk_alpha_pll_postdiv ne_gcc_gpll0_out_even = {
+	.offset = 0x0,
+	.post_div_shift = 10,
+	.post_div_table = post_div_table_ne_gcc_gpll0_out_even,
+	.num_post_div = ARRAY_SIZE(post_div_table_ne_gcc_gpll0_out_even),
+	.width = 4,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "ne_gcc_gpll0_out_even",
+		.parent_hws = (const struct clk_hw*[]) {
+			&ne_gcc_gpll0.clkr.hw,
+		},
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+	},
+};
+
+static struct clk_alpha_pll ne_gcc_gpll2 = {
+	.offset = 0x2000,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+	.clkr = {
+		.enable_reg = 0x0,
+		.enable_mask = BIT(2),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_gpll2",
+			.parent_data = &(const struct clk_parent_data) {
+				.index = DT_BI_TCXO,
+			},
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+		},
+	},
+};
+
+static const struct parent_map ne_gcc_parent_map_0[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_NE_GCC_GPLL0_OUT_MAIN, 1 },
+};
+
+static const struct clk_parent_data ne_gcc_parent_data_0[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &ne_gcc_gpll0.clkr.hw },
+};
+
+static const struct parent_map ne_gcc_parent_map_1[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_NE_GCC_GPLL0_OUT_MAIN, 1 },
+	{ P_NE_GCC_GPLL0_OUT_EVEN, 5 },
+};
+
+static const struct clk_parent_data ne_gcc_parent_data_1[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &ne_gcc_gpll0.clkr.hw },
+	{ .hw = &ne_gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map ne_gcc_parent_map_2[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_NE_GCC_GPLL0_OUT_MAIN, 1 },
+	{ P_NE_GCC_GPLL2_OUT_MAIN, 3 },
+};
+
+static const struct clk_parent_data ne_gcc_parent_data_2[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &ne_gcc_gpll0.clkr.hw },
+	{ .hw = &ne_gcc_gpll2.clkr.hw },
+};
+
+static const struct parent_map ne_gcc_parent_map_3[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_SLEEP_CLK, 5 },
+};
+
+static const struct clk_parent_data ne_gcc_parent_data_3[] = {
+	{ .index = DT_BI_TCXO },
+	{ .index = DT_SLEEP_CLK },
+};
+
+static const struct parent_map ne_gcc_parent_map_4[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_NE_GCC_GPLL0_OUT_MAIN, 1 },
+	{ P_SLEEP_CLK, 5 },
+};
+
+static const struct clk_parent_data ne_gcc_parent_data_4[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &ne_gcc_gpll0.clkr.hw },
+	{ .index = DT_SLEEP_CLK },
+};
+
+static const struct parent_map ne_gcc_parent_map_5[] = {
+	{ P_BI_TCXO, 0 },
+};
+
+static const struct clk_parent_data ne_gcc_parent_data_5[] = {
+	{ .index = DT_BI_TCXO },
+};
+
+static const struct parent_map ne_gcc_parent_map_6[] = {
+	{ P_USB3_PHY_WRAPPER_NE_GCC_USB31_PIPE_CLK, 0 },
+	{ P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data ne_gcc_parent_data_6[] = {
+	{ .index = DT_USB3_PHY_WRAPPER_NE_GCC_USB31_PIPE_CLK },
+	{ .index = DT_BI_TCXO },
+};
+
+static const struct parent_map ne_gcc_parent_map_7[] = {
+	{ P_USB3_PHY_SEC_WRAPPER_NE_GCC_USB31_PIPE_CLK, 0 },
+	{ P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data ne_gcc_parent_data_7[] = {
+	{ .index = DT_USB3_PHY_SEC_WRAPPER_NE_GCC_USB31_PIPE_CLK },
+	{ .index = DT_BI_TCXO },
+};
+
+static struct clk_regmap_phy_mux ne_gcc_ufs_phy_rx_symbol_0_clk_src = {
+	.reg = 0x33068,
+	.clkr = {
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_ufs_phy_rx_symbol_0_clk_src",
+			.parent_data = &(const struct clk_parent_data){
+				.index = DT_UFS_PHY_RX_SYMBOL_0_CLK,
+			},
+			.num_parents = 1,
+			.ops = &clk_regmap_phy_mux_ops,
+		},
+	},
+};
+
+static struct clk_regmap_phy_mux ne_gcc_ufs_phy_rx_symbol_1_clk_src = {
+	.reg = 0x330f0,
+	.clkr = {
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_ufs_phy_rx_symbol_1_clk_src",
+			.parent_data = &(const struct clk_parent_data){
+				.index = DT_UFS_PHY_RX_SYMBOL_1_CLK,
+			},
+			.num_parents = 1,
+			.ops = &clk_regmap_phy_mux_ops,
+		},
+	},
+};
+
+static struct clk_regmap_phy_mux ne_gcc_ufs_phy_tx_symbol_0_clk_src = {
+	.reg = 0x33058,
+	.clkr = {
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_ufs_phy_tx_symbol_0_clk_src",
+			.parent_data = &(const struct clk_parent_data){
+				.index = DT_UFS_PHY_TX_SYMBOL_0_CLK,
+			},
+			.num_parents = 1,
+			.ops = &clk_regmap_phy_mux_ops,
+		},
+	},
+};
+
+static struct clk_regmap_mux ne_gcc_usb3_prim_phy_pipe_clk_src = {
+	.reg = 0x2a078,
+	.shift = 0,
+	.width = 2,
+	.parent_map = ne_gcc_parent_map_6,
+	.clkr = {
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb3_prim_phy_pipe_clk_src",
+			.parent_data = ne_gcc_parent_data_6,
+			.num_parents = ARRAY_SIZE(ne_gcc_parent_data_6),
+			.ops = &clk_regmap_mux_closest_ops,
+		},
+	},
+};
+
+static struct clk_regmap_mux ne_gcc_usb3_sec_phy_pipe_clk_src = {
+	.reg = 0x2c078,
+	.shift = 0,
+	.width = 2,
+	.parent_map = ne_gcc_parent_map_7,
+	.clkr = {
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb3_sec_phy_pipe_clk_src",
+			.parent_data = ne_gcc_parent_data_7,
+			.num_parents = ARRAY_SIZE(ne_gcc_parent_data_7),
+			.ops = &clk_regmap_mux_closest_ops,
+		},
+	},
+};
+
+static const struct freq_tbl ftbl_ne_gcc_gp1_clk_src[] = {
+	F(66666667, P_NE_GCC_GPLL0_OUT_MAIN, 9, 0, 0),
+	F(100000000, P_NE_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+	F(200000000, P_NE_GCC_GPLL0_OUT_MAIN, 3, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 ne_gcc_gp1_clk_src = {
+	.cmd_rcgr = 0x21004,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_4,
+	.freq_tbl = ftbl_ne_gcc_gp1_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "ne_gcc_gp1_clk_src",
+		.parent_data = ne_gcc_parent_data_4,
+		.num_parents = ARRAY_SIZE(ne_gcc_parent_data_4),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 ne_gcc_gp2_clk_src = {
+	.cmd_rcgr = 0x22004,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_4,
+	.freq_tbl = ftbl_ne_gcc_gp1_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "ne_gcc_gp2_clk_src",
+		.parent_data = ne_gcc_parent_data_4,
+		.num_parents = ARRAY_SIZE(ne_gcc_parent_data_4),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_ne_gcc_qupv3_wrap2_s0_clk_src[] = {
+	F(7372800, P_NE_GCC_GPLL0_OUT_MAIN, 1, 192, 15625),
+	F(14745600, P_NE_GCC_GPLL0_OUT_MAIN, 1, 384, 15625),
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	F(29491200, P_NE_GCC_GPLL0_OUT_MAIN, 1, 768, 15625),
+	F(32000000, P_NE_GCC_GPLL0_OUT_MAIN, 1, 4, 75),
+	F(48000000, P_NE_GCC_GPLL0_OUT_MAIN, 1, 2, 25),
+	F(51200000, P_NE_GCC_GPLL0_OUT_MAIN, 1, 32, 375),
+	F(64000000, P_NE_GCC_GPLL0_OUT_MAIN, 1, 8, 75),
+	F(66666667, P_NE_GCC_GPLL0_OUT_MAIN, 9, 0, 0),
+	F(75000000, P_NE_GCC_GPLL0_OUT_MAIN, 8, 0, 0),
+	F(80000000, P_NE_GCC_GPLL0_OUT_MAIN, 1, 2, 15),
+	F(96000000, P_NE_GCC_GPLL0_OUT_MAIN, 1, 4, 25),
+	F(100000000, P_NE_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+	F(102400000, P_NE_GCC_GPLL0_OUT_MAIN, 1, 64, 375),
+	F(112000000, P_NE_GCC_GPLL0_OUT_MAIN, 1, 14, 75),
+	F(117964800, P_NE_GCC_GPLL0_OUT_MAIN, 1, 3072, 15625),
+	F(120000000, P_NE_GCC_GPLL0_OUT_MAIN, 5, 0, 0),
+	{ }
+};
+
+static struct clk_init_data ne_gcc_qupv3_wrap2_s0_clk_src_init = {
+	.name = "ne_gcc_qupv3_wrap2_s0_clk_src",
+	.parent_data = ne_gcc_parent_data_0,
+	.num_parents = ARRAY_SIZE(ne_gcc_parent_data_0),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 ne_gcc_qupv3_wrap2_s0_clk_src = {
+	.cmd_rcgr = 0x3816c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_0,
+	.freq_tbl = ftbl_ne_gcc_qupv3_wrap2_s0_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &ne_gcc_qupv3_wrap2_s0_clk_src_init,
+};
+
+static struct clk_init_data ne_gcc_qupv3_wrap2_s1_clk_src_init = {
+	.name = "ne_gcc_qupv3_wrap2_s1_clk_src",
+	.parent_data = ne_gcc_parent_data_0,
+	.num_parents = ARRAY_SIZE(ne_gcc_parent_data_0),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 ne_gcc_qupv3_wrap2_s1_clk_src = {
+	.cmd_rcgr = 0x382a8,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_0,
+	.freq_tbl = ftbl_ne_gcc_qupv3_wrap2_s0_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &ne_gcc_qupv3_wrap2_s1_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_ne_gcc_qupv3_wrap2_s2_clk_src[] = {
+	F(7372800, P_NE_GCC_GPLL0_OUT_MAIN, 1, 192, 15625),
+	F(14745600, P_NE_GCC_GPLL0_OUT_MAIN, 1, 384, 15625),
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	F(29491200, P_NE_GCC_GPLL0_OUT_MAIN, 1, 768, 15625),
+	F(32000000, P_NE_GCC_GPLL0_OUT_MAIN, 1, 4, 75),
+	F(48000000, P_NE_GCC_GPLL0_OUT_MAIN, 1, 2, 25),
+	F(51200000, P_NE_GCC_GPLL0_OUT_MAIN, 1, 32, 375),
+	F(64000000, P_NE_GCC_GPLL0_OUT_MAIN, 1, 8, 75),
+	F(66666667, P_NE_GCC_GPLL0_OUT_MAIN, 9, 0, 0),
+	F(75000000, P_NE_GCC_GPLL0_OUT_MAIN, 8, 0, 0),
+	F(80000000, P_NE_GCC_GPLL0_OUT_MAIN, 1, 2, 15),
+	F(96000000, P_NE_GCC_GPLL0_OUT_MAIN, 1, 4, 25),
+	F(100000000, P_NE_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+	{ }
+};
+
+static struct clk_init_data ne_gcc_qupv3_wrap2_s2_clk_src_init = {
+	.name = "ne_gcc_qupv3_wrap2_s2_clk_src",
+	.parent_data = ne_gcc_parent_data_0,
+	.num_parents = ARRAY_SIZE(ne_gcc_parent_data_0),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 ne_gcc_qupv3_wrap2_s2_clk_src = {
+	.cmd_rcgr = 0x383e4,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_0,
+	.freq_tbl = ftbl_ne_gcc_qupv3_wrap2_s2_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &ne_gcc_qupv3_wrap2_s2_clk_src_init,
+};
+
+static struct clk_init_data ne_gcc_qupv3_wrap2_s3_clk_src_init = {
+	.name = "ne_gcc_qupv3_wrap2_s3_clk_src",
+	.parent_data = ne_gcc_parent_data_0,
+	.num_parents = ARRAY_SIZE(ne_gcc_parent_data_0),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 ne_gcc_qupv3_wrap2_s3_clk_src = {
+	.cmd_rcgr = 0x38520,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_0,
+	.freq_tbl = ftbl_ne_gcc_qupv3_wrap2_s2_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &ne_gcc_qupv3_wrap2_s3_clk_src_init,
+};
+
+static struct clk_init_data ne_gcc_qupv3_wrap2_s4_clk_src_init = {
+	.name = "ne_gcc_qupv3_wrap2_s4_clk_src",
+	.parent_data = ne_gcc_parent_data_0,
+	.num_parents = ARRAY_SIZE(ne_gcc_parent_data_0),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 ne_gcc_qupv3_wrap2_s4_clk_src = {
+	.cmd_rcgr = 0x3865c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_0,
+	.freq_tbl = ftbl_ne_gcc_qupv3_wrap2_s2_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &ne_gcc_qupv3_wrap2_s4_clk_src_init,
+};
+
+static struct clk_init_data ne_gcc_qupv3_wrap2_s5_clk_src_init = {
+	.name = "ne_gcc_qupv3_wrap2_s5_clk_src",
+	.parent_data = ne_gcc_parent_data_0,
+	.num_parents = ARRAY_SIZE(ne_gcc_parent_data_0),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 ne_gcc_qupv3_wrap2_s5_clk_src = {
+	.cmd_rcgr = 0x38798,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_0,
+	.freq_tbl = ftbl_ne_gcc_qupv3_wrap2_s2_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &ne_gcc_qupv3_wrap2_s5_clk_src_init,
+};
+
+static struct clk_init_data ne_gcc_qupv3_wrap2_s6_clk_src_init = {
+	.name = "ne_gcc_qupv3_wrap2_s6_clk_src",
+	.parent_data = ne_gcc_parent_data_0,
+	.num_parents = ARRAY_SIZE(ne_gcc_parent_data_0),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 ne_gcc_qupv3_wrap2_s6_clk_src = {
+	.cmd_rcgr = 0x388d4,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_0,
+	.freq_tbl = ftbl_ne_gcc_qupv3_wrap2_s2_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &ne_gcc_qupv3_wrap2_s6_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_ne_gcc_sdcc4_apps_clk_src[] = {
+	F(37500000, P_NE_GCC_GPLL0_OUT_MAIN, 16, 0, 0),
+	F(50000000, P_NE_GCC_GPLL0_OUT_MAIN, 12, 0, 0),
+	F(100000000, P_NE_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 ne_gcc_sdcc4_apps_clk_src = {
+	.cmd_rcgr = 0x1801c,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_0,
+	.freq_tbl = ftbl_ne_gcc_sdcc4_apps_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "ne_gcc_sdcc4_apps_clk_src",
+		.parent_data = ne_gcc_parent_data_0,
+		.num_parents = ARRAY_SIZE(ne_gcc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_floor_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_ne_gcc_ufs_phy_axi_clk_src[] = {
+	F(120000000, P_NE_GCC_GPLL0_OUT_MAIN, 5, 0, 0),
+	F(201500000, P_NE_GCC_GPLL2_OUT_MAIN, 4, 0, 0),
+	F(300000000, P_NE_GCC_GPLL0_OUT_MAIN, 2, 0, 0),
+	F(403000000, P_NE_GCC_GPLL2_OUT_MAIN, 2, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 ne_gcc_ufs_phy_axi_clk_src = {
+	.cmd_rcgr = 0x33034,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_2,
+	.freq_tbl = ftbl_ne_gcc_ufs_phy_axi_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "ne_gcc_ufs_phy_axi_clk_src",
+		.parent_data = ne_gcc_parent_data_2,
+		.num_parents = ARRAY_SIZE(ne_gcc_parent_data_2),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 ne_gcc_ufs_phy_ice_core_clk_src = {
+	.cmd_rcgr = 0x3308c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_2,
+	.freq_tbl = ftbl_ne_gcc_ufs_phy_axi_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "ne_gcc_ufs_phy_ice_core_clk_src",
+		.parent_data = ne_gcc_parent_data_2,
+		.num_parents = ARRAY_SIZE(ne_gcc_parent_data_2),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_ne_gcc_ufs_phy_phy_aux_clk_src[] = {
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 ne_gcc_ufs_phy_phy_aux_clk_src = {
+	.cmd_rcgr = 0x330c0,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_5,
+	.freq_tbl = ftbl_ne_gcc_ufs_phy_phy_aux_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "ne_gcc_ufs_phy_phy_aux_clk_src",
+		.parent_data = ne_gcc_parent_data_5,
+		.num_parents = ARRAY_SIZE(ne_gcc_parent_data_5),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 ne_gcc_ufs_phy_unipro_core_clk_src = {
+	.cmd_rcgr = 0x330a4,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_2,
+	.freq_tbl = ftbl_ne_gcc_ufs_phy_axi_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "ne_gcc_ufs_phy_unipro_core_clk_src",
+		.parent_data = ne_gcc_parent_data_2,
+		.num_parents = ARRAY_SIZE(ne_gcc_parent_data_2),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_ne_gcc_usb20_master_clk_src[] = {
+	F(75000000, P_NE_GCC_GPLL0_OUT_MAIN, 8, 0, 0),
+	F(120000000, P_NE_GCC_GPLL0_OUT_MAIN, 5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 ne_gcc_usb20_master_clk_src = {
+	.cmd_rcgr = 0x31030,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_0,
+	.freq_tbl = ftbl_ne_gcc_usb20_master_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "ne_gcc_usb20_master_clk_src",
+		.parent_data = ne_gcc_parent_data_0,
+		.num_parents = ARRAY_SIZE(ne_gcc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 ne_gcc_usb20_mock_utmi_clk_src = {
+	.cmd_rcgr = 0x31048,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_0,
+	.freq_tbl = ftbl_ne_gcc_ufs_phy_phy_aux_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "ne_gcc_usb20_mock_utmi_clk_src",
+		.parent_data = ne_gcc_parent_data_0,
+		.num_parents = ARRAY_SIZE(ne_gcc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_ne_gcc_usb31_prim_master_clk_src[] = {
+	F(85714286, P_NE_GCC_GPLL0_OUT_MAIN, 7, 0, 0),
+	F(133333333, P_NE_GCC_GPLL0_OUT_MAIN, 4.5, 0, 0),
+	F(200000000, P_NE_GCC_GPLL0_OUT_MAIN, 3, 0, 0),
+	F(240000000, P_NE_GCC_GPLL0_OUT_MAIN, 2.5, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 ne_gcc_usb31_prim_master_clk_src = {
+	.cmd_rcgr = 0x2a038,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_1,
+	.freq_tbl = ftbl_ne_gcc_usb31_prim_master_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "ne_gcc_usb31_prim_master_clk_src",
+		.parent_data = ne_gcc_parent_data_1,
+		.num_parents = ARRAY_SIZE(ne_gcc_parent_data_1),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 ne_gcc_usb31_prim_mock_utmi_clk_src = {
+	.cmd_rcgr = 0x2a050,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_0,
+	.freq_tbl = ftbl_ne_gcc_ufs_phy_phy_aux_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "ne_gcc_usb31_prim_mock_utmi_clk_src",
+		.parent_data = ne_gcc_parent_data_0,
+		.num_parents = ARRAY_SIZE(ne_gcc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 ne_gcc_usb31_sec_master_clk_src = {
+	.cmd_rcgr = 0x2c038,
+	.mnd_width = 8,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_0,
+	.freq_tbl = ftbl_ne_gcc_usb31_prim_master_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "ne_gcc_usb31_sec_master_clk_src",
+		.parent_data = ne_gcc_parent_data_0,
+		.num_parents = ARRAY_SIZE(ne_gcc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 ne_gcc_usb31_sec_mock_utmi_clk_src = {
+	.cmd_rcgr = 0x2c050,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_0,
+	.freq_tbl = ftbl_ne_gcc_ufs_phy_phy_aux_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "ne_gcc_usb31_sec_mock_utmi_clk_src",
+		.parent_data = ne_gcc_parent_data_0,
+		.num_parents = ARRAY_SIZE(ne_gcc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 ne_gcc_usb3_prim_phy_aux_clk_src = {
+	.cmd_rcgr = 0x2a07c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_3,
+	.freq_tbl = ftbl_ne_gcc_ufs_phy_phy_aux_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "ne_gcc_usb3_prim_phy_aux_clk_src",
+		.parent_data = ne_gcc_parent_data_3,
+		.num_parents = ARRAY_SIZE(ne_gcc_parent_data_3),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 ne_gcc_usb3_sec_phy_aux_clk_src = {
+	.cmd_rcgr = 0x2c07c,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = ne_gcc_parent_map_3,
+	.freq_tbl = ftbl_ne_gcc_ufs_phy_phy_aux_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "ne_gcc_usb3_sec_phy_aux_clk_src",
+		.parent_data = ne_gcc_parent_data_3,
+		.num_parents = ARRAY_SIZE(ne_gcc_parent_data_3),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_regmap_div ne_gcc_usb20_mock_utmi_postdiv_clk_src = {
+	.reg = 0x31060,
+	.shift = 0,
+	.width = 4,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "ne_gcc_usb20_mock_utmi_postdiv_clk_src",
+		.parent_hws = (const struct clk_hw*[]) {
+			&ne_gcc_usb20_mock_utmi_clk_src.clkr.hw,
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_regmap_div_ro_ops,
+	},
+};
+
+static struct clk_regmap_div ne_gcc_usb31_prim_mock_utmi_postdiv_clk_src = {
+	.reg = 0x2a068,
+	.shift = 0,
+	.width = 4,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "ne_gcc_usb31_prim_mock_utmi_postdiv_clk_src",
+		.parent_hws = (const struct clk_hw*[]) {
+			&ne_gcc_usb31_prim_mock_utmi_clk_src.clkr.hw,
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_regmap_div_ro_ops,
+	},
+};
+
+static struct clk_regmap_div ne_gcc_usb31_sec_mock_utmi_postdiv_clk_src = {
+	.reg = 0x2c068,
+	.shift = 0,
+	.width = 4,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "ne_gcc_usb31_sec_mock_utmi_postdiv_clk_src",
+		.parent_hws = (const struct clk_hw*[]) {
+			&ne_gcc_usb31_sec_mock_utmi_clk_src.clkr.hw,
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_regmap_div_ro_ops,
+	},
+};
+
+static struct clk_branch ne_gcc_aggre_noc_ufs_phy_axi_clk = {
+	.halt_reg = 0x330f4,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x330f4,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x330f4,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_aggre_noc_ufs_phy_axi_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_ufs_phy_axi_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_aggre_noc_usb2_axi_clk = {
+	.halt_reg = 0x31068,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x31068,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x31068,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_aggre_noc_usb2_axi_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_usb20_master_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_aggre_noc_usb3_prim_axi_clk = {
+	.halt_reg = 0x2a098,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x2a098,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x2a098,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_aggre_noc_usb3_prim_axi_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_usb31_prim_master_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_aggre_noc_usb3_sec_axi_clk = {
+	.halt_reg = 0x2c098,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x2c098,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x2c098,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_aggre_noc_usb3_sec_axi_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_usb31_sec_master_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_ahb2phy_clk = {
+	.halt_reg = 0x30004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x30004,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x30004,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_ahb2phy_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_cnoc_usb2_axi_clk = {
+	.halt_reg = 0x31064,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x31064,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x31064,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_cnoc_usb2_axi_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_usb20_master_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_cnoc_usb3_prim_axi_clk = {
+	.halt_reg = 0x2a094,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x2a094,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x2a094,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_cnoc_usb3_prim_axi_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_usb31_prim_master_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_cnoc_usb3_sec_axi_clk = {
+	.halt_reg = 0x2c094,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x2c094,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x2c094,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_cnoc_usb3_sec_axi_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_usb31_sec_master_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_frq_measure_ref_clk = {
+	.halt_reg = 0x20008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x20008,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_frq_measure_ref_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_gp1_clk = {
+	.halt_reg = 0x21000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x21000,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_gp1_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_gp1_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_gp2_clk = {
+	.halt_reg = 0x22000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x22000,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_gp2_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_gp2_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_gpu_2_cfg_clk = {
+	.halt_reg = 0x34004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x34004,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x34004,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_gpu_2_cfg_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_gpu_2_gpll0_clk_src = {
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(19),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_gpu_2_gpll0_clk_src",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_gpll0.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_gpu_2_gpll0_div_clk_src = {
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(20),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_gpu_2_gpll0_div_clk_src",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_gpll0_out_even.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_gpu_2_hscnoc_gfx_clk = {
+	.halt_reg = 0x34014,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x34014,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x34014,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_gpu_2_hscnoc_gfx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_gpu_2_smmu_vote_clk = {
+	.halt_reg = 0x57028,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57028,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_gpu_2_smmu_vote_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_qupv3_wrap2_core_2x_clk = {
+	.halt_reg = 0x38020,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57008,
+		.enable_mask = BIT(1),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_qupv3_wrap2_core_2x_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_qupv3_wrap2_core_clk = {
+	.halt_reg = 0x3800c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57008,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_qupv3_wrap2_core_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_qupv3_wrap2_m_ahb_clk = {
+	.halt_reg = 0x38004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x38004,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(30),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_qupv3_wrap2_m_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_qupv3_wrap2_s0_clk = {
+	.halt_reg = 0x3815c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57008,
+		.enable_mask = BIT(2),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_qupv3_wrap2_s0_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_qupv3_wrap2_s0_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_qupv3_wrap2_s1_clk = {
+	.halt_reg = 0x38298,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57008,
+		.enable_mask = BIT(3),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_qupv3_wrap2_s1_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_qupv3_wrap2_s1_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_qupv3_wrap2_s2_clk = {
+	.halt_reg = 0x383d4,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57008,
+		.enable_mask = BIT(4),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_qupv3_wrap2_s2_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_qupv3_wrap2_s2_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_qupv3_wrap2_s3_clk = {
+	.halt_reg = 0x38510,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57008,
+		.enable_mask = BIT(5),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_qupv3_wrap2_s3_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_qupv3_wrap2_s3_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_qupv3_wrap2_s4_clk = {
+	.halt_reg = 0x3864c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57008,
+		.enable_mask = BIT(6),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_qupv3_wrap2_s4_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_qupv3_wrap2_s4_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_qupv3_wrap2_s5_clk = {
+	.halt_reg = 0x38788,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57008,
+		.enable_mask = BIT(7),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_qupv3_wrap2_s5_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_qupv3_wrap2_s5_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_qupv3_wrap2_s6_clk = {
+	.halt_reg = 0x388c4,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57008,
+		.enable_mask = BIT(8),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_qupv3_wrap2_s6_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_qupv3_wrap2_s6_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_qupv3_wrap2_s_ahb_clk = {
+	.halt_reg = 0x38008,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x38008,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(31),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_qupv3_wrap2_s_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_sdcc4_apps_clk = {
+	.halt_reg = 0x18004,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x18004,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_sdcc4_apps_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_sdcc4_apps_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_sdcc4_axi_clk = {
+	.halt_reg = 0x18014,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x18014,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_sdcc4_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_ufs_phy_ahb_clk = {
+	.halt_reg = 0x33028,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x33028,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x33028,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_ufs_phy_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_ufs_phy_axi_clk = {
+	.halt_reg = 0x33018,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x33018,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x33018,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_ufs_phy_axi_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_ufs_phy_axi_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_ufs_phy_ice_core_clk = {
+	.halt_reg = 0x3307c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x3307c,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x3307c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_ufs_phy_ice_core_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_ufs_phy_ice_core_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_ufs_phy_phy_aux_clk = {
+	.halt_reg = 0x330bc,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x330bc,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x330bc,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_ufs_phy_phy_aux_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_ufs_phy_phy_aux_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_ufs_phy_rx_symbol_0_clk = {
+	.halt_reg = 0x33030,
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x33030,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_ufs_phy_rx_symbol_0_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_ufs_phy_rx_symbol_0_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_ufs_phy_rx_symbol_1_clk = {
+	.halt_reg = 0x330d8,
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x330d8,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_ufs_phy_rx_symbol_1_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_ufs_phy_rx_symbol_1_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_ufs_phy_tx_symbol_0_clk = {
+	.halt_reg = 0x3302c,
+	.halt_check = BRANCH_HALT_DELAY,
+	.clkr = {
+		.enable_reg = 0x3302c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_ufs_phy_tx_symbol_0_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_ufs_phy_tx_symbol_0_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_ufs_phy_unipro_core_clk = {
+	.halt_reg = 0x3306c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x3306c,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x3306c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_ufs_phy_unipro_core_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_ufs_phy_unipro_core_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_usb20_master_clk = {
+	.halt_reg = 0x31018,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x31018,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb20_master_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_usb20_master_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_usb20_mock_utmi_clk = {
+	.halt_reg = 0x3102c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x3102c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb20_mock_utmi_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_usb20_mock_utmi_postdiv_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_usb20_sleep_clk = {
+	.halt_reg = 0x31028,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x31028,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb20_sleep_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_usb31_prim_atb_clk = {
+	.halt_reg = 0x2a018,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x2a018,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb31_prim_atb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_usb31_prim_master_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_usb31_prim_eud_ahb_clk = {
+	.halt_reg = 0x2a02c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x2a02c,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x2a02c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb31_prim_eud_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_usb31_prim_master_clk = {
+	.halt_reg = 0x2a01c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2a01c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb31_prim_master_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_usb31_prim_master_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_usb31_prim_mock_utmi_clk = {
+	.halt_reg = 0x2a034,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2a034,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb31_prim_mock_utmi_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_usb31_prim_mock_utmi_postdiv_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_usb31_prim_sleep_clk = {
+	.halt_reg = 0x2a030,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2a030,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb31_prim_sleep_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_usb31_sec_atb_clk = {
+	.halt_reg = 0x2c018,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x2c018,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb31_sec_atb_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_usb31_prim_master_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_usb31_sec_eud_ahb_clk = {
+	.halt_reg = 0x2c02c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x2c02c,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x2c02c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb31_sec_eud_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_usb31_sec_master_clk = {
+	.halt_reg = 0x2c01c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2c01c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb31_sec_master_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_usb31_sec_master_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_usb31_sec_mock_utmi_clk = {
+	.halt_reg = 0x2c034,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2c034,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb31_sec_mock_utmi_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_usb31_sec_mock_utmi_postdiv_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_usb31_sec_sleep_clk = {
+	.halt_reg = 0x2c030,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2c030,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb31_sec_sleep_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_usb3_prim_phy_aux_clk = {
+	.halt_reg = 0x2a06c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2a06c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb3_prim_phy_aux_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_usb3_prim_phy_com_aux_clk = {
+	.halt_reg = 0x2a070,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2a070,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb3_prim_phy_com_aux_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_usb3_prim_phy_pipe_clk = {
+	.halt_reg = 0x2a074,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x2a074,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x2a074,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb3_prim_phy_pipe_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_usb3_prim_phy_pipe_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_usb3_sec_phy_aux_clk = {
+	.halt_reg = 0x2c06c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2c06c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb3_sec_phy_aux_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_usb3_sec_phy_aux_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_usb3_sec_phy_com_aux_clk = {
+	.halt_reg = 0x2c070,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2c070,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb3_sec_phy_com_aux_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_usb3_sec_phy_aux_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch ne_gcc_usb3_sec_phy_pipe_clk = {
+	.halt_reg = 0x2c074,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x2c074,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x2c074,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "ne_gcc_usb3_sec_phy_pipe_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&ne_gcc_usb3_sec_phy_pipe_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct gdsc ne_gcc_ufs_mem_phy_gdsc = {
+	.gdscr = 0x32000,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0x2,
+	.pd = {
+		.name = "ne_gcc_ufs_mem_phy_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc ne_gcc_ufs_phy_gdsc = {
+	.gdscr = 0x33004,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0xf,
+	.pd = {
+		.name = "ne_gcc_ufs_phy_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc ne_gcc_usb20_prim_gdsc = {
+	.gdscr = 0x31004,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0xf,
+	.pd = {
+		.name = "ne_gcc_usb20_prim_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc ne_gcc_usb31_prim_gdsc = {
+	.gdscr = 0x2a004,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0xf,
+	.pd = {
+		.name = "ne_gcc_usb31_prim_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc ne_gcc_usb31_sec_gdsc = {
+	.gdscr = 0x2c004,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0xf,
+	.pd = {
+		.name = "ne_gcc_usb31_sec_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc ne_gcc_usb3_phy_gdsc = {
+	.gdscr = 0x2b00c,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0x2,
+	.pd = {
+		.name = "ne_gcc_usb3_phy_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc ne_gcc_usb3_sec_phy_gdsc = {
+	.gdscr = 0x2d00c,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0x2,
+	.pd = {
+		.name = "ne_gcc_usb3_sec_phy_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct clk_regmap *ne_gcc_nord_clocks[] = {
+	[NE_GCC_AGGRE_NOC_UFS_PHY_AXI_CLK] = &ne_gcc_aggre_noc_ufs_phy_axi_clk.clkr,
+	[NE_GCC_AGGRE_NOC_USB2_AXI_CLK] = &ne_gcc_aggre_noc_usb2_axi_clk.clkr,
+	[NE_GCC_AGGRE_NOC_USB3_PRIM_AXI_CLK] = &ne_gcc_aggre_noc_usb3_prim_axi_clk.clkr,
+	[NE_GCC_AGGRE_NOC_USB3_SEC_AXI_CLK] = &ne_gcc_aggre_noc_usb3_sec_axi_clk.clkr,
+	[NE_GCC_AHB2PHY_CLK] = &ne_gcc_ahb2phy_clk.clkr,
+	[NE_GCC_CNOC_USB2_AXI_CLK] = &ne_gcc_cnoc_usb2_axi_clk.clkr,
+	[NE_GCC_CNOC_USB3_PRIM_AXI_CLK] = &ne_gcc_cnoc_usb3_prim_axi_clk.clkr,
+	[NE_GCC_CNOC_USB3_SEC_AXI_CLK] = &ne_gcc_cnoc_usb3_sec_axi_clk.clkr,
+	[NE_GCC_FRQ_MEASURE_REF_CLK] = &ne_gcc_frq_measure_ref_clk.clkr,
+	[NE_GCC_GP1_CLK] = &ne_gcc_gp1_clk.clkr,
+	[NE_GCC_GP1_CLK_SRC] = &ne_gcc_gp1_clk_src.clkr,
+	[NE_GCC_GP2_CLK] = &ne_gcc_gp2_clk.clkr,
+	[NE_GCC_GP2_CLK_SRC] = &ne_gcc_gp2_clk_src.clkr,
+	[NE_GCC_GPLL0] = &ne_gcc_gpll0.clkr,
+	[NE_GCC_GPLL0_OUT_EVEN] = &ne_gcc_gpll0_out_even.clkr,
+	[NE_GCC_GPLL2] = &ne_gcc_gpll2.clkr,
+	[NE_GCC_GPU_2_CFG_CLK] = &ne_gcc_gpu_2_cfg_clk.clkr,
+	[NE_GCC_GPU_2_GPLL0_CLK_SRC] = &ne_gcc_gpu_2_gpll0_clk_src.clkr,
+	[NE_GCC_GPU_2_GPLL0_DIV_CLK_SRC] = &ne_gcc_gpu_2_gpll0_div_clk_src.clkr,
+	[NE_GCC_GPU_2_HSCNOC_GFX_CLK] = &ne_gcc_gpu_2_hscnoc_gfx_clk.clkr,
+	[NE_GCC_GPU_2_SMMU_VOTE_CLK] = &ne_gcc_gpu_2_smmu_vote_clk.clkr,
+	[NE_GCC_QUPV3_WRAP2_CORE_2X_CLK] = &ne_gcc_qupv3_wrap2_core_2x_clk.clkr,
+	[NE_GCC_QUPV3_WRAP2_CORE_CLK] = &ne_gcc_qupv3_wrap2_core_clk.clkr,
+	[NE_GCC_QUPV3_WRAP2_M_AHB_CLK] = &ne_gcc_qupv3_wrap2_m_ahb_clk.clkr,
+	[NE_GCC_QUPV3_WRAP2_S0_CLK] = &ne_gcc_qupv3_wrap2_s0_clk.clkr,
+	[NE_GCC_QUPV3_WRAP2_S0_CLK_SRC] = &ne_gcc_qupv3_wrap2_s0_clk_src.clkr,
+	[NE_GCC_QUPV3_WRAP2_S1_CLK] = &ne_gcc_qupv3_wrap2_s1_clk.clkr,
+	[NE_GCC_QUPV3_WRAP2_S1_CLK_SRC] = &ne_gcc_qupv3_wrap2_s1_clk_src.clkr,
+	[NE_GCC_QUPV3_WRAP2_S2_CLK] = &ne_gcc_qupv3_wrap2_s2_clk.clkr,
+	[NE_GCC_QUPV3_WRAP2_S2_CLK_SRC] = &ne_gcc_qupv3_wrap2_s2_clk_src.clkr,
+	[NE_GCC_QUPV3_WRAP2_S3_CLK] = &ne_gcc_qupv3_wrap2_s3_clk.clkr,
+	[NE_GCC_QUPV3_WRAP2_S3_CLK_SRC] = &ne_gcc_qupv3_wrap2_s3_clk_src.clkr,
+	[NE_GCC_QUPV3_WRAP2_S4_CLK] = &ne_gcc_qupv3_wrap2_s4_clk.clkr,
+	[NE_GCC_QUPV3_WRAP2_S4_CLK_SRC] = &ne_gcc_qupv3_wrap2_s4_clk_src.clkr,
+	[NE_GCC_QUPV3_WRAP2_S5_CLK] = &ne_gcc_qupv3_wrap2_s5_clk.clkr,
+	[NE_GCC_QUPV3_WRAP2_S5_CLK_SRC] = &ne_gcc_qupv3_wrap2_s5_clk_src.clkr,
+	[NE_GCC_QUPV3_WRAP2_S6_CLK] = &ne_gcc_qupv3_wrap2_s6_clk.clkr,
+	[NE_GCC_QUPV3_WRAP2_S6_CLK_SRC] = &ne_gcc_qupv3_wrap2_s6_clk_src.clkr,
+	[NE_GCC_QUPV3_WRAP2_S_AHB_CLK] = &ne_gcc_qupv3_wrap2_s_ahb_clk.clkr,
+	[NE_GCC_SDCC4_APPS_CLK] = &ne_gcc_sdcc4_apps_clk.clkr,
+	[NE_GCC_SDCC4_APPS_CLK_SRC] = &ne_gcc_sdcc4_apps_clk_src.clkr,
+	[NE_GCC_SDCC4_AXI_CLK] = &ne_gcc_sdcc4_axi_clk.clkr,
+	[NE_GCC_UFS_PHY_AHB_CLK] = &ne_gcc_ufs_phy_ahb_clk.clkr,
+	[NE_GCC_UFS_PHY_AXI_CLK] = &ne_gcc_ufs_phy_axi_clk.clkr,
+	[NE_GCC_UFS_PHY_AXI_CLK_SRC] = &ne_gcc_ufs_phy_axi_clk_src.clkr,
+	[NE_GCC_UFS_PHY_ICE_CORE_CLK] = &ne_gcc_ufs_phy_ice_core_clk.clkr,
+	[NE_GCC_UFS_PHY_ICE_CORE_CLK_SRC] = &ne_gcc_ufs_phy_ice_core_clk_src.clkr,
+	[NE_GCC_UFS_PHY_PHY_AUX_CLK] = &ne_gcc_ufs_phy_phy_aux_clk.clkr,
+	[NE_GCC_UFS_PHY_PHY_AUX_CLK_SRC] = &ne_gcc_ufs_phy_phy_aux_clk_src.clkr,
+	[NE_GCC_UFS_PHY_RX_SYMBOL_0_CLK] = &ne_gcc_ufs_phy_rx_symbol_0_clk.clkr,
+	[NE_GCC_UFS_PHY_RX_SYMBOL_0_CLK_SRC] = &ne_gcc_ufs_phy_rx_symbol_0_clk_src.clkr,
+	[NE_GCC_UFS_PHY_RX_SYMBOL_1_CLK] = &ne_gcc_ufs_phy_rx_symbol_1_clk.clkr,
+	[NE_GCC_UFS_PHY_RX_SYMBOL_1_CLK_SRC] = &ne_gcc_ufs_phy_rx_symbol_1_clk_src.clkr,
+	[NE_GCC_UFS_PHY_TX_SYMBOL_0_CLK] = &ne_gcc_ufs_phy_tx_symbol_0_clk.clkr,
+	[NE_GCC_UFS_PHY_TX_SYMBOL_0_CLK_SRC] = &ne_gcc_ufs_phy_tx_symbol_0_clk_src.clkr,
+	[NE_GCC_UFS_PHY_UNIPRO_CORE_CLK] = &ne_gcc_ufs_phy_unipro_core_clk.clkr,
+	[NE_GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC] = &ne_gcc_ufs_phy_unipro_core_clk_src.clkr,
+	[NE_GCC_USB20_MASTER_CLK] = &ne_gcc_usb20_master_clk.clkr,
+	[NE_GCC_USB20_MASTER_CLK_SRC] = &ne_gcc_usb20_master_clk_src.clkr,
+	[NE_GCC_USB20_MOCK_UTMI_CLK] = &ne_gcc_usb20_mock_utmi_clk.clkr,
+	[NE_GCC_USB20_MOCK_UTMI_CLK_SRC] = &ne_gcc_usb20_mock_utmi_clk_src.clkr,
+	[NE_GCC_USB20_MOCK_UTMI_POSTDIV_CLK_SRC] = &ne_gcc_usb20_mock_utmi_postdiv_clk_src.clkr,
+	[NE_GCC_USB20_SLEEP_CLK] = &ne_gcc_usb20_sleep_clk.clkr,
+	[NE_GCC_USB31_PRIM_ATB_CLK] = &ne_gcc_usb31_prim_atb_clk.clkr,
+	[NE_GCC_USB31_PRIM_EUD_AHB_CLK] = &ne_gcc_usb31_prim_eud_ahb_clk.clkr,
+	[NE_GCC_USB31_PRIM_MASTER_CLK] = &ne_gcc_usb31_prim_master_clk.clkr,
+	[NE_GCC_USB31_PRIM_MASTER_CLK_SRC] = &ne_gcc_usb31_prim_master_clk_src.clkr,
+	[NE_GCC_USB31_PRIM_MOCK_UTMI_CLK] = &ne_gcc_usb31_prim_mock_utmi_clk.clkr,
+	[NE_GCC_USB31_PRIM_MOCK_UTMI_CLK_SRC] = &ne_gcc_usb31_prim_mock_utmi_clk_src.clkr,
+	[NE_GCC_USB31_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC] =
+		&ne_gcc_usb31_prim_mock_utmi_postdiv_clk_src.clkr,
+	[NE_GCC_USB31_PRIM_SLEEP_CLK] = &ne_gcc_usb31_prim_sleep_clk.clkr,
+	[NE_GCC_USB31_SEC_ATB_CLK] = &ne_gcc_usb31_sec_atb_clk.clkr,
+	[NE_GCC_USB31_SEC_EUD_AHB_CLK] = &ne_gcc_usb31_sec_eud_ahb_clk.clkr,
+	[NE_GCC_USB31_SEC_MASTER_CLK] = &ne_gcc_usb31_sec_master_clk.clkr,
+	[NE_GCC_USB31_SEC_MASTER_CLK_SRC] = &ne_gcc_usb31_sec_master_clk_src.clkr,
+	[NE_GCC_USB31_SEC_MOCK_UTMI_CLK] = &ne_gcc_usb31_sec_mock_utmi_clk.clkr,
+	[NE_GCC_USB31_SEC_MOCK_UTMI_CLK_SRC] = &ne_gcc_usb31_sec_mock_utmi_clk_src.clkr,
+	[NE_GCC_USB31_SEC_MOCK_UTMI_POSTDIV_CLK_SRC] =
+		&ne_gcc_usb31_sec_mock_utmi_postdiv_clk_src.clkr,
+	[NE_GCC_USB31_SEC_SLEEP_CLK] = &ne_gcc_usb31_sec_sleep_clk.clkr,
+	[NE_GCC_USB3_PRIM_PHY_AUX_CLK] = &ne_gcc_usb3_prim_phy_aux_clk.clkr,
+	[NE_GCC_USB3_PRIM_PHY_AUX_CLK_SRC] = &ne_gcc_usb3_prim_phy_aux_clk_src.clkr,
+	[NE_GCC_USB3_PRIM_PHY_COM_AUX_CLK] = &ne_gcc_usb3_prim_phy_com_aux_clk.clkr,
+	[NE_GCC_USB3_PRIM_PHY_PIPE_CLK] = &ne_gcc_usb3_prim_phy_pipe_clk.clkr,
+	[NE_GCC_USB3_PRIM_PHY_PIPE_CLK_SRC] = &ne_gcc_usb3_prim_phy_pipe_clk_src.clkr,
+	[NE_GCC_USB3_SEC_PHY_AUX_CLK] = &ne_gcc_usb3_sec_phy_aux_clk.clkr,
+	[NE_GCC_USB3_SEC_PHY_AUX_CLK_SRC] = &ne_gcc_usb3_sec_phy_aux_clk_src.clkr,
+	[NE_GCC_USB3_SEC_PHY_COM_AUX_CLK] = &ne_gcc_usb3_sec_phy_com_aux_clk.clkr,
+	[NE_GCC_USB3_SEC_PHY_PIPE_CLK] = &ne_gcc_usb3_sec_phy_pipe_clk.clkr,
+	[NE_GCC_USB3_SEC_PHY_PIPE_CLK_SRC] = &ne_gcc_usb3_sec_phy_pipe_clk_src.clkr,
+};
+
+static struct gdsc *ne_gcc_nord_gdscs[] = {
+	[NE_GCC_UFS_MEM_PHY_GDSC] = &ne_gcc_ufs_mem_phy_gdsc,
+	[NE_GCC_UFS_PHY_GDSC] = &ne_gcc_ufs_phy_gdsc,
+	[NE_GCC_USB20_PRIM_GDSC] = &ne_gcc_usb20_prim_gdsc,
+	[NE_GCC_USB31_PRIM_GDSC] = &ne_gcc_usb31_prim_gdsc,
+	[NE_GCC_USB31_SEC_GDSC] = &ne_gcc_usb31_sec_gdsc,
+	[NE_GCC_USB3_PHY_GDSC] = &ne_gcc_usb3_phy_gdsc,
+	[NE_GCC_USB3_SEC_PHY_GDSC] = &ne_gcc_usb3_sec_phy_gdsc,
+};
+
+static const struct qcom_reset_map ne_gcc_nord_resets[] = {
+	[NE_GCC_GPU_2_BCR] = { 0x34000 },
+	[NE_GCC_QUPV3_WRAPPER_2_BCR] = { 0x38000 },
+	[NE_GCC_SDCC4_BCR] = { 0x18000 },
+	[NE_GCC_UFS_PHY_BCR] = { 0x33000 },
+	[NE_GCC_USB20_PRIM_BCR] = { 0x31000 },
+	[NE_GCC_USB31_PRIM_BCR] = { 0x2a000 },
+	[NE_GCC_USB31_SEC_BCR] = { 0x2c000 },
+	[NE_GCC_USB3_DP_PHY_PRIM_BCR] = { 0x2b008 },
+	[NE_GCC_USB3_DP_PHY_SEC_BCR] = { 0x2d008 },
+	[NE_GCC_USB3_PHY_PRIM_BCR] = { 0x2b000 },
+	[NE_GCC_USB3_PHY_SEC_BCR] = { 0x2d000 },
+	[NE_GCC_USB3PHY_PHY_PRIM_BCR] = { 0x2b004 },
+	[NE_GCC_USB3PHY_PHY_SEC_BCR] = { 0x2d004 },
+};
+
+static const struct clk_rcg_dfs_data ne_gcc_nord_dfs_clocks[] = {
+	DEFINE_RCG_DFS(ne_gcc_qupv3_wrap2_s0_clk_src),
+	DEFINE_RCG_DFS(ne_gcc_qupv3_wrap2_s1_clk_src),
+	DEFINE_RCG_DFS(ne_gcc_qupv3_wrap2_s2_clk_src),
+	DEFINE_RCG_DFS(ne_gcc_qupv3_wrap2_s3_clk_src),
+	DEFINE_RCG_DFS(ne_gcc_qupv3_wrap2_s4_clk_src),
+	DEFINE_RCG_DFS(ne_gcc_qupv3_wrap2_s5_clk_src),
+	DEFINE_RCG_DFS(ne_gcc_qupv3_wrap2_s6_clk_src),
+};
+
+static const struct regmap_config ne_gcc_nord_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = 0xf41f0,
+	.fast_io = true,
+};
+
+static void clk_nord_regs_configure(struct device *dev, struct regmap *regmap)
+{
+	/* FORCE_MEM_CORE_ON for  ne_gcc_ufs_phy_ice_core_clk and ne_gcc_ufs_phy_axi_clk */
+	qcom_branch_set_force_mem_core(regmap, ne_gcc_ufs_phy_ice_core_clk, true);
+	qcom_branch_set_force_mem_core(regmap, ne_gcc_ufs_phy_axi_clk, true);
+}
+
+static struct qcom_cc_driver_data ne_gcc_nord_driver_data = {
+	.dfs_rcgs = ne_gcc_nord_dfs_clocks,
+	.num_dfs_rcgs = ARRAY_SIZE(ne_gcc_nord_dfs_clocks),
+	.clk_regs_configure = clk_nord_regs_configure,
+};
+
+static const struct qcom_cc_desc ne_gcc_nord_desc = {
+	.config = &ne_gcc_nord_regmap_config,
+	.clks = ne_gcc_nord_clocks,
+	.num_clks = ARRAY_SIZE(ne_gcc_nord_clocks),
+	.resets = ne_gcc_nord_resets,
+	.num_resets = ARRAY_SIZE(ne_gcc_nord_resets),
+	.gdscs = ne_gcc_nord_gdscs,
+	.num_gdscs = ARRAY_SIZE(ne_gcc_nord_gdscs),
+	.driver_data = &ne_gcc_nord_driver_data,
+};
+
+static const struct of_device_id ne_gcc_nord_match_table[] = {
+	{ .compatible = "qcom,nord-negcc" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ne_gcc_nord_match_table);
+
+static int ne_gcc_nord_probe(struct platform_device *pdev)
+{
+	return qcom_cc_probe(pdev, &ne_gcc_nord_desc);
+}
+
+static struct platform_driver ne_gcc_nord_driver = {
+	.probe = ne_gcc_nord_probe,
+	.driver = {
+		.name = "negcc-nord",
+		.of_match_table = ne_gcc_nord_match_table,
+	},
+};
+
+module_platform_driver(ne_gcc_nord_driver);
+
+MODULE_DESCRIPTION("QTI NEGCC NORD Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/nwgcc-nord.c b/drivers/clk/qcom/nwgcc-nord.c
new file mode 100644
index 0000000000000000000000000000000000000000..163ab63c872bc7d5132d68bf0ec3e05f5814974d
--- /dev/null
+++ b/drivers/clk/qcom/nwgcc-nord.c
@@ -0,0 +1,688 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,nord-nwgcc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+#include "common.h"
+#include "reset.h"
+
+enum {
+	DT_BI_TCXO,
+	DT_SLEEP_CLK,
+};
+
+enum {
+	P_BI_TCXO,
+	P_NW_GCC_GPLL0_OUT_EVEN,
+	P_NW_GCC_GPLL0_OUT_MAIN,
+	P_SLEEP_CLK,
+};
+
+static struct clk_alpha_pll nw_gcc_gpll0 = {
+	.offset = 0x0,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+	.clkr = {
+		.enable_reg = 0x0,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_gpll0",
+			.parent_data = &(const struct clk_parent_data) {
+				.index = DT_BI_TCXO,
+			},
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+		},
+	},
+};
+
+static const struct clk_div_table post_div_table_nw_gcc_gpll0_out_even[] = {
+	{ 0x1, 2 },
+	{ }
+};
+
+static struct clk_alpha_pll_postdiv nw_gcc_gpll0_out_even = {
+	.offset = 0x0,
+	.post_div_shift = 10,
+	.post_div_table = post_div_table_nw_gcc_gpll0_out_even,
+	.num_post_div = ARRAY_SIZE(post_div_table_nw_gcc_gpll0_out_even),
+	.width = 4,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "nw_gcc_gpll0_out_even",
+		.parent_hws = (const struct clk_hw*[]) {
+			&nw_gcc_gpll0.clkr.hw,
+		},
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+	},
+};
+
+static const struct parent_map nw_gcc_parent_map_0[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_NW_GCC_GPLL0_OUT_MAIN, 1 },
+	{ P_SLEEP_CLK, 5 },
+	{ P_NW_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data nw_gcc_parent_data_0[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &nw_gcc_gpll0.clkr.hw },
+	{ .index = DT_SLEEP_CLK },
+	{ .hw = &nw_gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct freq_tbl ftbl_nw_gcc_gp1_clk_src[] = {
+	F(60000000, P_NW_GCC_GPLL0_OUT_MAIN, 10, 0, 0),
+	F(100000000, P_NW_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+	F(200000000, P_NW_GCC_GPLL0_OUT_MAIN, 3, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 nw_gcc_gp1_clk_src = {
+	.cmd_rcgr = 0x20004,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = nw_gcc_parent_map_0,
+	.freq_tbl = ftbl_nw_gcc_gp1_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "nw_gcc_gp1_clk_src",
+		.parent_data = nw_gcc_parent_data_0,
+		.num_parents = ARRAY_SIZE(nw_gcc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 nw_gcc_gp2_clk_src = {
+	.cmd_rcgr = 0x21004,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = nw_gcc_parent_map_0,
+	.freq_tbl = ftbl_nw_gcc_gp1_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "nw_gcc_gp2_clk_src",
+		.parent_data = nw_gcc_parent_data_0,
+		.num_parents = ARRAY_SIZE(nw_gcc_parent_data_0),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_branch nw_gcc_acmu_mux_clk = {
+	.halt_reg = 0x1f01c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1f01c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_acmu_mux_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_camera_hf_axi_clk = {
+	.halt_reg = 0x16008,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x16008,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x16008,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_camera_hf_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_camera_sf_axi_clk = {
+	.halt_reg = 0x1601c,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x1601c,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x1601c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_camera_sf_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_camera_trig_clk = {
+	.halt_reg = 0x16034,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x16034,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x16034,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_camera_trig_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_disp_0_hf_axi_clk = {
+	.halt_reg = 0x18008,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x18008,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x18008,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_disp_0_hf_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_disp_0_trig_clk = {
+	.halt_reg = 0x1801c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x1801c,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x1801c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_disp_0_trig_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_disp_1_hf_axi_clk = {
+	.halt_reg = 0x19008,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x19008,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x19008,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_disp_1_hf_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_disp_1_trig_clk = {
+	.halt_reg = 0x1901c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x1901c,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x1901c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_disp_1_trig_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_dprx0_axi_hf_clk = {
+	.halt_reg = 0x29004,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x29004,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x29004,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_dprx0_axi_hf_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_dprx1_axi_hf_clk = {
+	.halt_reg = 0x2a004,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x2a004,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x2a004,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_dprx1_axi_hf_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_eva_axi0_clk = {
+	.halt_reg = 0x1b008,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x1b008,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x1b008,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_eva_axi0_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_eva_axi0c_clk = {
+	.halt_reg = 0x1b01c,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x1b01c,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x1b01c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_eva_axi0c_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_eva_trig_clk = {
+	.halt_reg = 0x1b028,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x1b028,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x1b028,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_eva_trig_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_frq_measure_ref_clk = {
+	.halt_reg = 0x1f008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1f008,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_frq_measure_ref_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_gp1_clk = {
+	.halt_reg = 0x20000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x20000,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_gp1_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&nw_gcc_gp1_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_gp2_clk = {
+	.halt_reg = 0x21000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x21000,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_gp2_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&nw_gcc_gp2_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_gpu_2_gpll0_clk_src = {
+	.halt_reg = 0x24150,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x24150,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x76000,
+		.enable_mask = BIT(6),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_gpu_2_gpll0_clk_src",
+			.parent_hws = (const struct clk_hw*[]) {
+				&nw_gcc_gpll0.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_gpu_2_gpll0_div_clk_src = {
+	.halt_reg = 0x24158,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x24158,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x76000,
+		.enable_mask = BIT(7),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_gpu_2_gpll0_div_clk_src",
+			.parent_hws = (const struct clk_hw*[]) {
+				&nw_gcc_gpll0_out_even.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_gpu_2_hscnoc_gfx_clk = {
+	.halt_reg = 0x2400c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x2400c,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x2400c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_gpu_2_hscnoc_gfx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_gpu_gpll0_clk_src = {
+	.halt_reg = 0x23150,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x23150,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x76000,
+		.enable_mask = BIT(4),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_gpu_gpll0_clk_src",
+			.parent_hws = (const struct clk_hw*[]) {
+				&nw_gcc_gpll0.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_gpu_gpll0_div_clk_src = {
+	.halt_reg = 0x23158,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x23158,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x76000,
+		.enable_mask = BIT(5),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_gpu_gpll0_div_clk_src",
+			.parent_hws = (const struct clk_hw*[]) {
+				&nw_gcc_gpll0_out_even.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_gpu_hscnoc_gfx_clk = {
+	.halt_reg = 0x2300c,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x2300c,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x2300c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_gpu_hscnoc_gfx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_gpu_smmu_vote_clk = {
+	.halt_reg = 0x86038,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x86038,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_gpu_smmu_vote_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_hscnoc_gpu_2_axi_clk = {
+	.halt_reg = 0x24160,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x24160,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x24160,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_hscnoc_gpu_2_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_hscnoc_gpu_axi_clk = {
+	.halt_reg = 0x23160,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x23160,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x23160,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_hscnoc_gpu_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_mmu_1_tcu_vote_clk = {
+	.halt_reg = 0x86040,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x86040,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_mmu_1_tcu_vote_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_video_axi0_clk = {
+	.halt_reg = 0x1a008,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x1a008,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x1a008,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_video_axi0_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_video_axi0c_clk = {
+	.halt_reg = 0x1a01c,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x1a01c,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x1a01c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_video_axi0c_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch nw_gcc_video_axi1_clk = {
+	.halt_reg = 0x1a030,
+	.halt_check = BRANCH_HALT_SKIP,
+	.hwcg_reg = 0x1a030,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x1a030,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "nw_gcc_video_axi1_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_regmap *nw_gcc_nord_clocks[] = {
+	[NW_GCC_ACMU_MUX_CLK] = &nw_gcc_acmu_mux_clk.clkr,
+	[NW_GCC_CAMERA_HF_AXI_CLK] = &nw_gcc_camera_hf_axi_clk.clkr,
+	[NW_GCC_CAMERA_SF_AXI_CLK] = &nw_gcc_camera_sf_axi_clk.clkr,
+	[NW_GCC_CAMERA_TRIG_CLK] = &nw_gcc_camera_trig_clk.clkr,
+	[NW_GCC_DISP_0_HF_AXI_CLK] = &nw_gcc_disp_0_hf_axi_clk.clkr,
+	[NW_GCC_DISP_0_TRIG_CLK] = &nw_gcc_disp_0_trig_clk.clkr,
+	[NW_GCC_DISP_1_HF_AXI_CLK] = &nw_gcc_disp_1_hf_axi_clk.clkr,
+	[NW_GCC_DISP_1_TRIG_CLK] = &nw_gcc_disp_1_trig_clk.clkr,
+	[NW_GCC_DPRX0_AXI_HF_CLK] = &nw_gcc_dprx0_axi_hf_clk.clkr,
+	[NW_GCC_DPRX1_AXI_HF_CLK] = &nw_gcc_dprx1_axi_hf_clk.clkr,
+	[NW_GCC_EVA_AXI0_CLK] = &nw_gcc_eva_axi0_clk.clkr,
+	[NW_GCC_EVA_AXI0C_CLK] = &nw_gcc_eva_axi0c_clk.clkr,
+	[NW_GCC_EVA_TRIG_CLK] = &nw_gcc_eva_trig_clk.clkr,
+	[NW_GCC_FRQ_MEASURE_REF_CLK] = &nw_gcc_frq_measure_ref_clk.clkr,
+	[NW_GCC_GP1_CLK] = &nw_gcc_gp1_clk.clkr,
+	[NW_GCC_GP1_CLK_SRC] = &nw_gcc_gp1_clk_src.clkr,
+	[NW_GCC_GP2_CLK] = &nw_gcc_gp2_clk.clkr,
+	[NW_GCC_GP2_CLK_SRC] = &nw_gcc_gp2_clk_src.clkr,
+	[NW_GCC_GPLL0] = &nw_gcc_gpll0.clkr,
+	[NW_GCC_GPLL0_OUT_EVEN] = &nw_gcc_gpll0_out_even.clkr,
+	[NW_GCC_GPU_2_GPLL0_CLK_SRC] = &nw_gcc_gpu_2_gpll0_clk_src.clkr,
+	[NW_GCC_GPU_2_GPLL0_DIV_CLK_SRC] = &nw_gcc_gpu_2_gpll0_div_clk_src.clkr,
+	[NW_GCC_GPU_2_HSCNOC_GFX_CLK] = &nw_gcc_gpu_2_hscnoc_gfx_clk.clkr,
+	[NW_GCC_GPU_GPLL0_CLK_SRC] = &nw_gcc_gpu_gpll0_clk_src.clkr,
+	[NW_GCC_GPU_GPLL0_DIV_CLK_SRC] = &nw_gcc_gpu_gpll0_div_clk_src.clkr,
+	[NW_GCC_GPU_HSCNOC_GFX_CLK] = &nw_gcc_gpu_hscnoc_gfx_clk.clkr,
+	[NW_GCC_GPU_SMMU_VOTE_CLK] = &nw_gcc_gpu_smmu_vote_clk.clkr,
+	[NW_GCC_HSCNOC_GPU_2_AXI_CLK] = &nw_gcc_hscnoc_gpu_2_axi_clk.clkr,
+	[NW_GCC_HSCNOC_GPU_AXI_CLK] = &nw_gcc_hscnoc_gpu_axi_clk.clkr,
+	[NW_GCC_MMU_1_TCU_VOTE_CLK] = &nw_gcc_mmu_1_tcu_vote_clk.clkr,
+	[NW_GCC_VIDEO_AXI0_CLK] = &nw_gcc_video_axi0_clk.clkr,
+	[NW_GCC_VIDEO_AXI0C_CLK] = &nw_gcc_video_axi0c_clk.clkr,
+	[NW_GCC_VIDEO_AXI1_CLK] = &nw_gcc_video_axi1_clk.clkr,
+};
+
+static const struct qcom_reset_map nw_gcc_nord_resets[] = {
+	[NW_GCC_CAMERA_BCR] = { 0x16000 },
+	[NW_GCC_DISPLAY_0_BCR] = { 0x18000 },
+	[NW_GCC_DISPLAY_1_BCR] = { 0x19000 },
+	[NW_GCC_DPRX0_BCR] = { 0x29000 },
+	[NW_GCC_DPRX1_BCR] = { 0x2a000 },
+	[NW_GCC_EVA_BCR] = { 0x1b000 },
+	[NW_GCC_GPU_2_BCR] = { 0x24000 },
+	[NW_GCC_GPU_BCR] = { 0x23000 },
+	[NW_GCC_VIDEO_BCR] = { 0x1a000 },
+};
+
+static u32 nw_gcc_nord_critical_cbcrs[] = {
+	0x16004, /* NW_GCC_CAMERA_AHB_CLK */
+	0x16030, /* NW_GCC_CAMERA_XO_CLK */
+	0x18004, /* NW_GCC_DISP_0_AHB_CLK */
+	0x19004, /* NW_GCC_DISP_1_AHB_CLK */
+	0x29018, /* NW_GCC_DPRX0_CFG_AHB_CLK */
+	0x2a018, /* NW_GCC_DPRX1_CFG_AHB_CLK */
+	0x1b004, /* NW_GCC_EVA_AHB_CLK */
+	0x1b024, /* NW_GCC_EVA_XO_CLK */
+	0x23004, /* NW_GCC_GPU_CFG_AHB_CLK */
+	0x24004, /* NW_GCC_GPU_2_CFG_AHB_CLK */
+	0x1a004, /* NW_GCC_VIDEO_AHB_CLK */
+	0x1a044, /* NW_GCC_VIDEO_XO_CLK */
+};
+
+static struct qcom_cc_driver_data nw_gcc_nord_driver_data = {
+	.clk_cbcrs = nw_gcc_nord_critical_cbcrs,
+	.num_clk_cbcrs = ARRAY_SIZE(nw_gcc_nord_critical_cbcrs),
+};
+
+static const struct regmap_config nw_gcc_nord_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = 0xf41f0,
+	.fast_io = true,
+};
+
+static const struct qcom_cc_desc nw_gcc_nord_desc = {
+	.config = &nw_gcc_nord_regmap_config,
+	.clks = nw_gcc_nord_clocks,
+	.num_clks = ARRAY_SIZE(nw_gcc_nord_clocks),
+	.resets = nw_gcc_nord_resets,
+	.num_resets = ARRAY_SIZE(nw_gcc_nord_resets),
+	.driver_data = &nw_gcc_nord_driver_data,
+};
+
+static const struct of_device_id nw_gcc_nord_match_table[] = {
+	{ .compatible = "qcom,nord-nwgcc" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, nw_gcc_nord_match_table);
+
+static int nw_gcc_nord_probe(struct platform_device *pdev)
+{
+	return qcom_cc_probe(pdev, &nw_gcc_nord_desc);
+}
+
+static struct platform_driver nw_gcc_nord_driver = {
+	.probe = nw_gcc_nord_probe,
+	.driver = {
+		.name = "nwgcc-nord",
+		.of_match_table = nw_gcc_nord_match_table,
+	},
+};
+
+module_platform_driver(nw_gcc_nord_driver);
+
+MODULE_DESCRIPTION("QTI NWGCC NORD Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/segcc-nord.c b/drivers/clk/qcom/segcc-nord.c
new file mode 100644
index 0000000000000000000000000000000000000000..1aab0999de4dde7262bd694f7d7f955b2a9cb66e
--- /dev/null
+++ b/drivers/clk/qcom/segcc-nord.c
@@ -0,0 +1,1609 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,nord-segcc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "common.h"
+#include "gdsc.h"
+#include "reset.h"
+
+enum {
+	DT_BI_TCXO,
+	DT_SLEEP_CLK,
+};
+
+enum {
+	P_BI_TCXO,
+	P_SE_GCC_GPLL0_OUT_EVEN,
+	P_SE_GCC_GPLL0_OUT_MAIN,
+	P_SE_GCC_GPLL2_OUT_MAIN,
+	P_SE_GCC_GPLL4_OUT_MAIN,
+	P_SE_GCC_GPLL5_OUT_MAIN,
+	P_SLEEP_CLK,
+};
+
+static struct clk_alpha_pll se_gcc_gpll0 = {
+	.offset = 0x0,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+	.clkr = {
+		.enable_reg = 0x0,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_gpll0",
+			.parent_data = &(const struct clk_parent_data) {
+				.index = DT_BI_TCXO,
+			},
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+		},
+	},
+};
+
+static const struct clk_div_table post_div_table_se_gcc_gpll0_out_even[] = {
+	{ 0x1, 2 },
+	{ }
+};
+
+static struct clk_alpha_pll_postdiv se_gcc_gpll0_out_even = {
+	.offset = 0x0,
+	.post_div_shift = 10,
+	.post_div_table = post_div_table_se_gcc_gpll0_out_even,
+	.num_post_div = ARRAY_SIZE(post_div_table_se_gcc_gpll0_out_even),
+	.width = 4,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "se_gcc_gpll0_out_even",
+		.parent_hws = (const struct clk_hw*[]) {
+			&se_gcc_gpll0.clkr.hw,
+		},
+		.num_parents = 1,
+		.ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+	},
+};
+
+static struct clk_alpha_pll se_gcc_gpll2 = {
+	.offset = 0x2000,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+	.clkr = {
+		.enable_reg = 0x0,
+		.enable_mask = BIT(2),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_gpll2",
+			.parent_data = &(const struct clk_parent_data) {
+				.index = DT_BI_TCXO,
+			},
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+		},
+	},
+};
+
+static struct clk_alpha_pll se_gcc_gpll4 = {
+	.offset = 0x4000,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+	.clkr = {
+		.enable_reg = 0x0,
+		.enable_mask = BIT(4),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_gpll4",
+			.parent_data = &(const struct clk_parent_data) {
+				.index = DT_BI_TCXO,
+			},
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+		},
+	},
+};
+
+static struct clk_alpha_pll se_gcc_gpll5 = {
+	.offset = 0x5000,
+	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+	.clkr = {
+		.enable_reg = 0x0,
+		.enable_mask = BIT(5),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_gpll5",
+			.parent_data = &(const struct clk_parent_data) {
+				.index = DT_BI_TCXO,
+			},
+			.num_parents = 1,
+			.ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+		},
+	},
+};
+
+static const struct parent_map se_gcc_parent_map_0[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_SE_GCC_GPLL0_OUT_MAIN, 1 },
+	{ P_SE_GCC_GPLL0_OUT_EVEN, 2 },
+};
+
+static const struct clk_parent_data se_gcc_parent_data_0[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &se_gcc_gpll0.clkr.hw },
+	{ .hw = &se_gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map se_gcc_parent_map_1[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_SE_GCC_GPLL0_OUT_MAIN, 1 },
+};
+
+static const struct clk_parent_data se_gcc_parent_data_1[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &se_gcc_gpll0.clkr.hw },
+};
+
+static const struct parent_map se_gcc_parent_map_2[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_SE_GCC_GPLL0_OUT_MAIN, 1 },
+	{ P_SLEEP_CLK, 5 },
+};
+
+static const struct clk_parent_data se_gcc_parent_data_2[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &se_gcc_gpll0.clkr.hw },
+	{ .index = DT_SLEEP_CLK },
+};
+
+static const struct parent_map se_gcc_parent_map_3[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_SE_GCC_GPLL0_OUT_MAIN, 1 },
+	{ P_SE_GCC_GPLL5_OUT_MAIN, 3 },
+	{ P_SE_GCC_GPLL4_OUT_MAIN, 5 },
+	{ P_SE_GCC_GPLL2_OUT_MAIN, 6 },
+};
+
+static const struct clk_parent_data se_gcc_parent_data_3[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &se_gcc_gpll0.clkr.hw },
+	{ .hw = &se_gcc_gpll5.clkr.hw },
+	{ .hw = &se_gcc_gpll4.clkr.hw },
+	{ .hw = &se_gcc_gpll2.clkr.hw },
+};
+
+static const struct parent_map se_gcc_parent_map_4[] = {
+	{ P_BI_TCXO, 0 },
+	{ P_SE_GCC_GPLL0_OUT_MAIN, 1 },
+	{ P_SE_GCC_GPLL0_OUT_EVEN, 2 },
+	{ P_SLEEP_CLK, 5 },
+};
+
+static const struct clk_parent_data se_gcc_parent_data_4[] = {
+	{ .index = DT_BI_TCXO },
+	{ .hw = &se_gcc_gpll0.clkr.hw },
+	{ .hw = &se_gcc_gpll0_out_even.clkr.hw },
+	{ .index = DT_SLEEP_CLK },
+};
+
+static const struct freq_tbl ftbl_se_gcc_eee_emac0_clk_src[] = {
+	F(66666667, P_SE_GCC_GPLL0_OUT_MAIN, 9, 0, 0),
+	F(100000000, P_SE_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 se_gcc_eee_emac0_clk_src = {
+	.cmd_rcgr = 0x240b8,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_2,
+	.freq_tbl = ftbl_se_gcc_eee_emac0_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "se_gcc_eee_emac0_clk_src",
+		.parent_data = se_gcc_parent_data_2,
+		.num_parents = ARRAY_SIZE(se_gcc_parent_data_2),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 se_gcc_eee_emac1_clk_src = {
+	.cmd_rcgr = 0x250b8,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_2,
+	.freq_tbl = ftbl_se_gcc_eee_emac0_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "se_gcc_eee_emac1_clk_src",
+		.parent_data = se_gcc_parent_data_2,
+		.num_parents = ARRAY_SIZE(se_gcc_parent_data_2),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_se_gcc_emac0_phy_aux_clk_src[] = {
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 se_gcc_emac0_phy_aux_clk_src = {
+	.cmd_rcgr = 0x24030,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_2,
+	.freq_tbl = ftbl_se_gcc_emac0_phy_aux_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "se_gcc_emac0_phy_aux_clk_src",
+		.parent_data = se_gcc_parent_data_2,
+		.num_parents = ARRAY_SIZE(se_gcc_parent_data_2),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_se_gcc_emac0_ptp_clk_src[] = {
+	F(150000000, P_SE_GCC_GPLL0_OUT_MAIN, 4, 0, 0),
+	F(250000000, P_SE_GCC_GPLL5_OUT_MAIN, 4, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 se_gcc_emac0_ptp_clk_src = {
+	.cmd_rcgr = 0x24084,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_3,
+	.freq_tbl = ftbl_se_gcc_emac0_ptp_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "se_gcc_emac0_ptp_clk_src",
+		.parent_data = se_gcc_parent_data_3,
+		.num_parents = ARRAY_SIZE(se_gcc_parent_data_3),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_se_gcc_emac0_rgmii_clk_src[] = {
+	F(75000000, P_SE_GCC_GPLL0_OUT_MAIN, 8, 0, 0),
+	F(120000000, P_SE_GCC_GPLL0_OUT_MAIN, 5, 0, 0),
+	F(250000000, P_SE_GCC_GPLL5_OUT_MAIN, 4, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 se_gcc_emac0_rgmii_clk_src = {
+	.cmd_rcgr = 0x2406c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_3,
+	.freq_tbl = ftbl_se_gcc_emac0_rgmii_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "se_gcc_emac0_rgmii_clk_src",
+		.parent_data = se_gcc_parent_data_3,
+		.num_parents = ARRAY_SIZE(se_gcc_parent_data_3),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 se_gcc_emac1_phy_aux_clk_src = {
+	.cmd_rcgr = 0x25030,
+	.mnd_width = 0,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_2,
+	.freq_tbl = ftbl_se_gcc_emac0_phy_aux_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "se_gcc_emac1_phy_aux_clk_src",
+		.parent_data = se_gcc_parent_data_2,
+		.num_parents = ARRAY_SIZE(se_gcc_parent_data_2),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 se_gcc_emac1_ptp_clk_src = {
+	.cmd_rcgr = 0x25084,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_3,
+	.freq_tbl = ftbl_se_gcc_emac0_ptp_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "se_gcc_emac1_ptp_clk_src",
+		.parent_data = se_gcc_parent_data_3,
+		.num_parents = ARRAY_SIZE(se_gcc_parent_data_3),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 se_gcc_emac1_rgmii_clk_src = {
+	.cmd_rcgr = 0x2506c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_3,
+	.freq_tbl = ftbl_se_gcc_emac0_rgmii_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "se_gcc_emac1_rgmii_clk_src",
+		.parent_data = se_gcc_parent_data_3,
+		.num_parents = ARRAY_SIZE(se_gcc_parent_data_3),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_se_gcc_gp1_clk_src[] = {
+	F(66666667, P_SE_GCC_GPLL0_OUT_MAIN, 9, 0, 0),
+	F(100000000, P_SE_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+	F(200000000, P_SE_GCC_GPLL0_OUT_MAIN, 3, 0, 0),
+	{ }
+};
+
+static struct clk_rcg2 se_gcc_gp1_clk_src = {
+	.cmd_rcgr = 0x19004,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_4,
+	.freq_tbl = ftbl_se_gcc_gp1_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "se_gcc_gp1_clk_src",
+		.parent_data = se_gcc_parent_data_4,
+		.num_parents = ARRAY_SIZE(se_gcc_parent_data_4),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static struct clk_rcg2 se_gcc_gp2_clk_src = {
+	.cmd_rcgr = 0x1a004,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_4,
+	.freq_tbl = ftbl_se_gcc_gp1_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &(const struct clk_init_data) {
+		.name = "se_gcc_gp2_clk_src",
+		.parent_data = se_gcc_parent_data_4,
+		.num_parents = ARRAY_SIZE(se_gcc_parent_data_4),
+		.flags = CLK_SET_RATE_PARENT,
+		.ops = &clk_rcg2_shared_ops,
+	},
+};
+
+static const struct freq_tbl ftbl_se_gcc_qupv3_wrap0_s0_clk_src[] = {
+	F(7372800, P_SE_GCC_GPLL0_OUT_MAIN, 1, 192, 15625),
+	F(14745600, P_SE_GCC_GPLL0_OUT_MAIN, 1, 384, 15625),
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	F(29491200, P_SE_GCC_GPLL0_OUT_MAIN, 1, 768, 15625),
+	F(32000000, P_SE_GCC_GPLL0_OUT_MAIN, 1, 4, 75),
+	F(48000000, P_SE_GCC_GPLL0_OUT_MAIN, 1, 2, 25),
+	F(51200000, P_SE_GCC_GPLL0_OUT_MAIN, 1, 32, 375),
+	F(64000000, P_SE_GCC_GPLL0_OUT_MAIN, 1, 8, 75),
+	F(66666667, P_SE_GCC_GPLL0_OUT_MAIN, 9, 0, 0),
+	F(75000000, P_SE_GCC_GPLL0_OUT_MAIN, 8, 0, 0),
+	F(80000000, P_SE_GCC_GPLL0_OUT_MAIN, 1, 2, 15),
+	F(96000000, P_SE_GCC_GPLL0_OUT_MAIN, 1, 4, 25),
+	F(100000000, P_SE_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+	F(102400000, P_SE_GCC_GPLL0_OUT_MAIN, 1, 64, 375),
+	F(112000000, P_SE_GCC_GPLL0_OUT_MAIN, 1, 14, 75),
+	F(117964800, P_SE_GCC_GPLL0_OUT_MAIN, 1, 3072, 15625),
+	F(120000000, P_SE_GCC_GPLL0_OUT_MAIN, 5, 0, 0),
+	{ }
+};
+
+static struct clk_init_data se_gcc_qupv3_wrap0_s0_clk_src_init = {
+	.name = "se_gcc_qupv3_wrap0_s0_clk_src",
+	.parent_data = se_gcc_parent_data_1,
+	.num_parents = ARRAY_SIZE(se_gcc_parent_data_1),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 se_gcc_qupv3_wrap0_s0_clk_src = {
+	.cmd_rcgr = 0x2616c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_1,
+	.freq_tbl = ftbl_se_gcc_qupv3_wrap0_s0_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &se_gcc_qupv3_wrap0_s0_clk_src_init,
+};
+
+static struct clk_init_data se_gcc_qupv3_wrap0_s1_clk_src_init = {
+	.name = "se_gcc_qupv3_wrap0_s1_clk_src",
+	.parent_data = se_gcc_parent_data_1,
+	.num_parents = ARRAY_SIZE(se_gcc_parent_data_1),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 se_gcc_qupv3_wrap0_s1_clk_src = {
+	.cmd_rcgr = 0x262a8,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_1,
+	.freq_tbl = ftbl_se_gcc_qupv3_wrap0_s0_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &se_gcc_qupv3_wrap0_s1_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_se_gcc_qupv3_wrap0_s2_clk_src[] = {
+	F(7372800, P_SE_GCC_GPLL0_OUT_MAIN, 1, 192, 15625),
+	F(14745600, P_SE_GCC_GPLL0_OUT_MAIN, 1, 384, 15625),
+	F(19200000, P_BI_TCXO, 1, 0, 0),
+	F(29491200, P_SE_GCC_GPLL0_OUT_MAIN, 1, 768, 15625),
+	F(32000000, P_SE_GCC_GPLL0_OUT_MAIN, 1, 4, 75),
+	F(48000000, P_SE_GCC_GPLL0_OUT_MAIN, 1, 2, 25),
+	F(51200000, P_SE_GCC_GPLL0_OUT_MAIN, 1, 32, 375),
+	F(64000000, P_SE_GCC_GPLL0_OUT_MAIN, 1, 8, 75),
+	F(66666667, P_SE_GCC_GPLL0_OUT_MAIN, 9, 0, 0),
+	F(75000000, P_SE_GCC_GPLL0_OUT_MAIN, 8, 0, 0),
+	F(80000000, P_SE_GCC_GPLL0_OUT_MAIN, 1, 2, 15),
+	F(96000000, P_SE_GCC_GPLL0_OUT_MAIN, 1, 4, 25),
+	F(100000000, P_SE_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+	{ }
+};
+
+static struct clk_init_data se_gcc_qupv3_wrap0_s2_clk_src_init = {
+	.name = "se_gcc_qupv3_wrap0_s2_clk_src",
+	.parent_data = se_gcc_parent_data_1,
+	.num_parents = ARRAY_SIZE(se_gcc_parent_data_1),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 se_gcc_qupv3_wrap0_s2_clk_src = {
+	.cmd_rcgr = 0x263e4,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_1,
+	.freq_tbl = ftbl_se_gcc_qupv3_wrap0_s2_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &se_gcc_qupv3_wrap0_s2_clk_src_init,
+};
+
+static struct clk_init_data se_gcc_qupv3_wrap0_s3_clk_src_init = {
+	.name = "se_gcc_qupv3_wrap0_s3_clk_src",
+	.parent_data = se_gcc_parent_data_1,
+	.num_parents = ARRAY_SIZE(se_gcc_parent_data_1),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 se_gcc_qupv3_wrap0_s3_clk_src = {
+	.cmd_rcgr = 0x26520,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_1,
+	.freq_tbl = ftbl_se_gcc_qupv3_wrap0_s2_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &se_gcc_qupv3_wrap0_s3_clk_src_init,
+};
+
+static struct clk_init_data se_gcc_qupv3_wrap0_s4_clk_src_init = {
+	.name = "se_gcc_qupv3_wrap0_s4_clk_src",
+	.parent_data = se_gcc_parent_data_1,
+	.num_parents = ARRAY_SIZE(se_gcc_parent_data_1),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 se_gcc_qupv3_wrap0_s4_clk_src = {
+	.cmd_rcgr = 0x2665c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_1,
+	.freq_tbl = ftbl_se_gcc_qupv3_wrap0_s2_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &se_gcc_qupv3_wrap0_s4_clk_src_init,
+};
+
+static struct clk_init_data se_gcc_qupv3_wrap0_s5_clk_src_init = {
+	.name = "se_gcc_qupv3_wrap0_s5_clk_src",
+	.parent_data = se_gcc_parent_data_1,
+	.num_parents = ARRAY_SIZE(se_gcc_parent_data_1),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 se_gcc_qupv3_wrap0_s5_clk_src = {
+	.cmd_rcgr = 0x26798,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_1,
+	.freq_tbl = ftbl_se_gcc_qupv3_wrap0_s2_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &se_gcc_qupv3_wrap0_s5_clk_src_init,
+};
+
+static struct clk_init_data se_gcc_qupv3_wrap0_s6_clk_src_init = {
+	.name = "se_gcc_qupv3_wrap0_s6_clk_src",
+	.parent_data = se_gcc_parent_data_1,
+	.num_parents = ARRAY_SIZE(se_gcc_parent_data_1),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 se_gcc_qupv3_wrap0_s6_clk_src = {
+	.cmd_rcgr = 0x268d4,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_1,
+	.freq_tbl = ftbl_se_gcc_qupv3_wrap0_s2_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &se_gcc_qupv3_wrap0_s6_clk_src_init,
+};
+
+static struct clk_init_data se_gcc_qupv3_wrap1_s0_clk_src_init = {
+	.name = "se_gcc_qupv3_wrap1_s0_clk_src",
+	.parent_data = se_gcc_parent_data_0,
+	.num_parents = ARRAY_SIZE(se_gcc_parent_data_0),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 se_gcc_qupv3_wrap1_s0_clk_src = {
+	.cmd_rcgr = 0x2716c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_0,
+	.freq_tbl = ftbl_se_gcc_qupv3_wrap0_s0_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &se_gcc_qupv3_wrap1_s0_clk_src_init,
+};
+
+static struct clk_init_data se_gcc_qupv3_wrap1_s1_clk_src_init = {
+	.name = "se_gcc_qupv3_wrap1_s1_clk_src",
+	.parent_data = se_gcc_parent_data_0,
+	.num_parents = ARRAY_SIZE(se_gcc_parent_data_0),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 se_gcc_qupv3_wrap1_s1_clk_src = {
+	.cmd_rcgr = 0x272a8,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_0,
+	.freq_tbl = ftbl_se_gcc_qupv3_wrap0_s0_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &se_gcc_qupv3_wrap1_s1_clk_src_init,
+};
+
+static struct clk_init_data se_gcc_qupv3_wrap1_s2_clk_src_init = {
+	.name = "se_gcc_qupv3_wrap1_s2_clk_src",
+	.parent_data = se_gcc_parent_data_0,
+	.num_parents = ARRAY_SIZE(se_gcc_parent_data_0),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 se_gcc_qupv3_wrap1_s2_clk_src = {
+	.cmd_rcgr = 0x273e4,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_0,
+	.freq_tbl = ftbl_se_gcc_qupv3_wrap0_s2_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &se_gcc_qupv3_wrap1_s2_clk_src_init,
+};
+
+static struct clk_init_data se_gcc_qupv3_wrap1_s3_clk_src_init = {
+	.name = "se_gcc_qupv3_wrap1_s3_clk_src",
+	.parent_data = se_gcc_parent_data_0,
+	.num_parents = ARRAY_SIZE(se_gcc_parent_data_0),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 se_gcc_qupv3_wrap1_s3_clk_src = {
+	.cmd_rcgr = 0x27520,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_0,
+	.freq_tbl = ftbl_se_gcc_qupv3_wrap0_s2_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &se_gcc_qupv3_wrap1_s3_clk_src_init,
+};
+
+static struct clk_init_data se_gcc_qupv3_wrap1_s4_clk_src_init = {
+	.name = "se_gcc_qupv3_wrap1_s4_clk_src",
+	.parent_data = se_gcc_parent_data_0,
+	.num_parents = ARRAY_SIZE(se_gcc_parent_data_0),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 se_gcc_qupv3_wrap1_s4_clk_src = {
+	.cmd_rcgr = 0x2765c,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_0,
+	.freq_tbl = ftbl_se_gcc_qupv3_wrap0_s2_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &se_gcc_qupv3_wrap1_s4_clk_src_init,
+};
+
+static struct clk_init_data se_gcc_qupv3_wrap1_s5_clk_src_init = {
+	.name = "se_gcc_qupv3_wrap1_s5_clk_src",
+	.parent_data = se_gcc_parent_data_0,
+	.num_parents = ARRAY_SIZE(se_gcc_parent_data_0),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 se_gcc_qupv3_wrap1_s5_clk_src = {
+	.cmd_rcgr = 0x27798,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_0,
+	.freq_tbl = ftbl_se_gcc_qupv3_wrap0_s2_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &se_gcc_qupv3_wrap1_s5_clk_src_init,
+};
+
+static struct clk_init_data se_gcc_qupv3_wrap1_s6_clk_src_init = {
+	.name = "se_gcc_qupv3_wrap1_s6_clk_src",
+	.parent_data = se_gcc_parent_data_0,
+	.num_parents = ARRAY_SIZE(se_gcc_parent_data_0),
+	.flags = CLK_SET_RATE_PARENT,
+	.ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 se_gcc_qupv3_wrap1_s6_clk_src = {
+	.cmd_rcgr = 0x278d4,
+	.mnd_width = 16,
+	.hid_width = 5,
+	.parent_map = se_gcc_parent_map_0,
+	.freq_tbl = ftbl_se_gcc_qupv3_wrap0_s2_clk_src,
+	.hw_clk_ctrl = true,
+	.clkr.hw.init = &se_gcc_qupv3_wrap1_s6_clk_src_init,
+};
+
+static struct clk_branch se_gcc_eee_emac0_clk = {
+	.halt_reg = 0x240b4,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x240b4,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_eee_emac0_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_eee_emac0_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_eee_emac1_clk = {
+	.halt_reg = 0x250b4,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x250b4,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_eee_emac1_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_eee_emac1_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_emac0_axi_clk = {
+	.halt_reg = 0x2401c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x2401c,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x2401c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_emac0_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_emac0_cc_sgmiiphy_rx_clk = {
+	.halt_reg = 0x24064,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x24064,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_emac0_cc_sgmiiphy_rx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_emac0_cc_sgmiiphy_tx_clk = {
+	.halt_reg = 0x2405c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2405c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_emac0_cc_sgmiiphy_tx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_emac0_phy_aux_clk = {
+	.halt_reg = 0x2402c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2402c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_emac0_phy_aux_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_emac0_phy_aux_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_emac0_ptp_clk = {
+	.halt_reg = 0x24048,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x24048,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_emac0_ptp_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_emac0_ptp_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_emac0_rgmii_clk = {
+	.halt_reg = 0x24058,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x24058,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_emac0_rgmii_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_emac0_rgmii_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_emac0_rpcs_rx_clk = {
+	.halt_reg = 0x240a8,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x240a8,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_emac0_rpcs_rx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_emac0_rpcs_tx_clk = {
+	.halt_reg = 0x240a4,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x240a4,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_emac0_rpcs_tx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_emac0_xgxs_rx_clk = {
+	.halt_reg = 0x240b0,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x240b0,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_emac0_xgxs_rx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_emac0_xgxs_tx_clk = {
+	.halt_reg = 0x240ac,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x240ac,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_emac0_xgxs_tx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_emac1_axi_clk = {
+	.halt_reg = 0x2501c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x2501c,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x2501c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_emac1_axi_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_emac1_cc_sgmiiphy_rx_clk = {
+	.halt_reg = 0x25064,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x25064,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_emac1_cc_sgmiiphy_rx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_emac1_cc_sgmiiphy_tx_clk = {
+	.halt_reg = 0x2505c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2505c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_emac1_cc_sgmiiphy_tx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_emac1_phy_aux_clk = {
+	.halt_reg = 0x2502c,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x2502c,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_emac1_phy_aux_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_emac1_phy_aux_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_emac1_ptp_clk = {
+	.halt_reg = 0x25048,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x25048,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_emac1_ptp_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_emac1_ptp_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_emac1_rgmii_clk = {
+	.halt_reg = 0x25058,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x25058,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_emac1_rgmii_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_emac1_rgmii_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_emac1_rpcs_rx_clk = {
+	.halt_reg = 0x250a8,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x250a8,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_emac1_rpcs_rx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_emac1_rpcs_tx_clk = {
+	.halt_reg = 0x250a4,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x250a4,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_emac1_rpcs_tx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_emac1_xgxs_rx_clk = {
+	.halt_reg = 0x250b0,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x250b0,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_emac1_xgxs_rx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_emac1_xgxs_tx_clk = {
+	.halt_reg = 0x250ac,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x250ac,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_emac1_xgxs_tx_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_frq_measure_ref_clk = {
+	.halt_reg = 0x18008,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x18008,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_frq_measure_ref_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_gp1_clk = {
+	.halt_reg = 0x19000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x19000,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_gp1_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_gp1_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_gp2_clk = {
+	.halt_reg = 0x1a000,
+	.halt_check = BRANCH_HALT,
+	.clkr = {
+		.enable_reg = 0x1a000,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_gp2_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_gp2_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_mmu_2_tcu_vote_clk = {
+	.halt_reg = 0x57040,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57040,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_mmu_2_tcu_vote_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap0_core_2x_clk = {
+	.halt_reg = 0x26020,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(15),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap0_core_2x_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap0_core_clk = {
+	.halt_reg = 0x2600c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(14),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap0_core_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap0_m_ahb_clk = {
+	.halt_reg = 0x26004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x26004,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(12),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap0_m_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap0_s0_clk = {
+	.halt_reg = 0x2615c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(16),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap0_s0_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_qupv3_wrap0_s0_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap0_s1_clk = {
+	.halt_reg = 0x26298,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(17),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap0_s1_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_qupv3_wrap0_s1_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap0_s2_clk = {
+	.halt_reg = 0x263d4,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(18),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap0_s2_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_qupv3_wrap0_s2_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap0_s3_clk = {
+	.halt_reg = 0x26510,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(19),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap0_s3_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_qupv3_wrap0_s3_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap0_s4_clk = {
+	.halt_reg = 0x2664c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(20),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap0_s4_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_qupv3_wrap0_s4_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap0_s5_clk = {
+	.halt_reg = 0x26788,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(21),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap0_s5_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_qupv3_wrap0_s5_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap0_s6_clk = {
+	.halt_reg = 0x268c4,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(22),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap0_s6_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_qupv3_wrap0_s6_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap0_s_ahb_clk = {
+	.halt_reg = 0x26008,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x26008,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(13),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap0_s_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap1_core_2x_clk = {
+	.halt_reg = 0x27020,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(26),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap1_core_2x_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap1_core_clk = {
+	.halt_reg = 0x2700c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(25),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap1_core_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap1_m_ahb_clk = {
+	.halt_reg = 0x27004,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x27004,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(23),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap1_m_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap1_s0_clk = {
+	.halt_reg = 0x2715c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(27),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap1_s0_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_qupv3_wrap1_s0_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap1_s1_clk = {
+	.halt_reg = 0x27298,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(28),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap1_s1_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_qupv3_wrap1_s1_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap1_s2_clk = {
+	.halt_reg = 0x273d4,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(29),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap1_s2_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_qupv3_wrap1_s2_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap1_s3_clk = {
+	.halt_reg = 0x27510,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(30),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap1_s3_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_qupv3_wrap1_s3_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap1_s4_clk = {
+	.halt_reg = 0x2764c,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(31),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap1_s4_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_qupv3_wrap1_s4_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap1_s5_clk = {
+	.halt_reg = 0x27788,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57008,
+		.enable_mask = BIT(0),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap1_s5_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_qupv3_wrap1_s5_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap1_s6_clk = {
+	.halt_reg = 0x278c4,
+	.halt_check = BRANCH_HALT_VOTED,
+	.clkr = {
+		.enable_reg = 0x57008,
+		.enable_mask = BIT(1),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap1_s6_clk",
+			.parent_hws = (const struct clk_hw*[]) {
+				&se_gcc_qupv3_wrap1_s6_clk_src.clkr.hw,
+			},
+			.num_parents = 1,
+			.flags = CLK_SET_RATE_PARENT,
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct clk_branch se_gcc_qupv3_wrap1_s_ahb_clk = {
+	.halt_reg = 0x27008,
+	.halt_check = BRANCH_HALT_VOTED,
+	.hwcg_reg = 0x27008,
+	.hwcg_bit = 1,
+	.clkr = {
+		.enable_reg = 0x57000,
+		.enable_mask = BIT(24),
+		.hw.init = &(const struct clk_init_data) {
+			.name = "se_gcc_qupv3_wrap1_s_ahb_clk",
+			.ops = &clk_branch2_ops,
+		},
+	},
+};
+
+static struct gdsc se_gcc_emac0_gdsc = {
+	.gdscr = 0x24004,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0xf,
+	.pd = {
+		.name = "se_gcc_emac0_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc se_gcc_emac1_gdsc = {
+	.gdscr = 0x25004,
+	.en_rest_wait_val = 0x2,
+	.en_few_wait_val = 0x2,
+	.clk_dis_wait_val = 0xf,
+	.pd = {
+		.name = "se_gcc_emac1_gdsc",
+	},
+	.pwrsts = PWRSTS_OFF_ON,
+	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct clk_regmap *se_gcc_nord_clocks[] = {
+	[SE_GCC_EEE_EMAC0_CLK] = &se_gcc_eee_emac0_clk.clkr,
+	[SE_GCC_EEE_EMAC0_CLK_SRC] = &se_gcc_eee_emac0_clk_src.clkr,
+	[SE_GCC_EEE_EMAC1_CLK] = &se_gcc_eee_emac1_clk.clkr,
+	[SE_GCC_EEE_EMAC1_CLK_SRC] = &se_gcc_eee_emac1_clk_src.clkr,
+	[SE_GCC_EMAC0_AXI_CLK] = &se_gcc_emac0_axi_clk.clkr,
+	[SE_GCC_EMAC0_CC_SGMIIPHY_RX_CLK] = &se_gcc_emac0_cc_sgmiiphy_rx_clk.clkr,
+	[SE_GCC_EMAC0_CC_SGMIIPHY_TX_CLK] = &se_gcc_emac0_cc_sgmiiphy_tx_clk.clkr,
+	[SE_GCC_EMAC0_PHY_AUX_CLK] = &se_gcc_emac0_phy_aux_clk.clkr,
+	[SE_GCC_EMAC0_PHY_AUX_CLK_SRC] = &se_gcc_emac0_phy_aux_clk_src.clkr,
+	[SE_GCC_EMAC0_PTP_CLK] = &se_gcc_emac0_ptp_clk.clkr,
+	[SE_GCC_EMAC0_PTP_CLK_SRC] = &se_gcc_emac0_ptp_clk_src.clkr,
+	[SE_GCC_EMAC0_RGMII_CLK] = &se_gcc_emac0_rgmii_clk.clkr,
+	[SE_GCC_EMAC0_RGMII_CLK_SRC] = &se_gcc_emac0_rgmii_clk_src.clkr,
+	[SE_GCC_EMAC0_RPCS_RX_CLK] = &se_gcc_emac0_rpcs_rx_clk.clkr,
+	[SE_GCC_EMAC0_RPCS_TX_CLK] = &se_gcc_emac0_rpcs_tx_clk.clkr,
+	[SE_GCC_EMAC0_XGXS_RX_CLK] = &se_gcc_emac0_xgxs_rx_clk.clkr,
+	[SE_GCC_EMAC0_XGXS_TX_CLK] = &se_gcc_emac0_xgxs_tx_clk.clkr,
+	[SE_GCC_EMAC1_AXI_CLK] = &se_gcc_emac1_axi_clk.clkr,
+	[SE_GCC_EMAC1_CC_SGMIIPHY_RX_CLK] = &se_gcc_emac1_cc_sgmiiphy_rx_clk.clkr,
+	[SE_GCC_EMAC1_CC_SGMIIPHY_TX_CLK] = &se_gcc_emac1_cc_sgmiiphy_tx_clk.clkr,
+	[SE_GCC_EMAC1_PHY_AUX_CLK] = &se_gcc_emac1_phy_aux_clk.clkr,
+	[SE_GCC_EMAC1_PHY_AUX_CLK_SRC] = &se_gcc_emac1_phy_aux_clk_src.clkr,
+	[SE_GCC_EMAC1_PTP_CLK] = &se_gcc_emac1_ptp_clk.clkr,
+	[SE_GCC_EMAC1_PTP_CLK_SRC] = &se_gcc_emac1_ptp_clk_src.clkr,
+	[SE_GCC_EMAC1_RGMII_CLK] = &se_gcc_emac1_rgmii_clk.clkr,
+	[SE_GCC_EMAC1_RGMII_CLK_SRC] = &se_gcc_emac1_rgmii_clk_src.clkr,
+	[SE_GCC_EMAC1_RPCS_RX_CLK] = &se_gcc_emac1_rpcs_rx_clk.clkr,
+	[SE_GCC_EMAC1_RPCS_TX_CLK] = &se_gcc_emac1_rpcs_tx_clk.clkr,
+	[SE_GCC_EMAC1_XGXS_RX_CLK] = &se_gcc_emac1_xgxs_rx_clk.clkr,
+	[SE_GCC_EMAC1_XGXS_TX_CLK] = &se_gcc_emac1_xgxs_tx_clk.clkr,
+	[SE_GCC_FRQ_MEASURE_REF_CLK] = &se_gcc_frq_measure_ref_clk.clkr,
+	[SE_GCC_GP1_CLK] = &se_gcc_gp1_clk.clkr,
+	[SE_GCC_GP1_CLK_SRC] = &se_gcc_gp1_clk_src.clkr,
+	[SE_GCC_GP2_CLK] = &se_gcc_gp2_clk.clkr,
+	[SE_GCC_GP2_CLK_SRC] = &se_gcc_gp2_clk_src.clkr,
+	[SE_GCC_GPLL0] = &se_gcc_gpll0.clkr,
+	[SE_GCC_GPLL0_OUT_EVEN] = &se_gcc_gpll0_out_even.clkr,
+	[SE_GCC_GPLL2] = &se_gcc_gpll2.clkr,
+	[SE_GCC_GPLL4] = &se_gcc_gpll4.clkr,
+	[SE_GCC_GPLL5] = &se_gcc_gpll5.clkr,
+	[SE_GCC_MMU_2_TCU_VOTE_CLK] = &se_gcc_mmu_2_tcu_vote_clk.clkr,
+	[SE_GCC_QUPV3_WRAP0_CORE_2X_CLK] = &se_gcc_qupv3_wrap0_core_2x_clk.clkr,
+	[SE_GCC_QUPV3_WRAP0_CORE_CLK] = &se_gcc_qupv3_wrap0_core_clk.clkr,
+	[SE_GCC_QUPV3_WRAP0_M_AHB_CLK] = &se_gcc_qupv3_wrap0_m_ahb_clk.clkr,
+	[SE_GCC_QUPV3_WRAP0_S0_CLK] = &se_gcc_qupv3_wrap0_s0_clk.clkr,
+	[SE_GCC_QUPV3_WRAP0_S0_CLK_SRC] = &se_gcc_qupv3_wrap0_s0_clk_src.clkr,
+	[SE_GCC_QUPV3_WRAP0_S1_CLK] = &se_gcc_qupv3_wrap0_s1_clk.clkr,
+	[SE_GCC_QUPV3_WRAP0_S1_CLK_SRC] = &se_gcc_qupv3_wrap0_s1_clk_src.clkr,
+	[SE_GCC_QUPV3_WRAP0_S2_CLK] = &se_gcc_qupv3_wrap0_s2_clk.clkr,
+	[SE_GCC_QUPV3_WRAP0_S2_CLK_SRC] = &se_gcc_qupv3_wrap0_s2_clk_src.clkr,
+	[SE_GCC_QUPV3_WRAP0_S3_CLK] = &se_gcc_qupv3_wrap0_s3_clk.clkr,
+	[SE_GCC_QUPV3_WRAP0_S3_CLK_SRC] = &se_gcc_qupv3_wrap0_s3_clk_src.clkr,
+	[SE_GCC_QUPV3_WRAP0_S4_CLK] = &se_gcc_qupv3_wrap0_s4_clk.clkr,
+	[SE_GCC_QUPV3_WRAP0_S4_CLK_SRC] = &se_gcc_qupv3_wrap0_s4_clk_src.clkr,
+	[SE_GCC_QUPV3_WRAP0_S5_CLK] = &se_gcc_qupv3_wrap0_s5_clk.clkr,
+	[SE_GCC_QUPV3_WRAP0_S5_CLK_SRC] = &se_gcc_qupv3_wrap0_s5_clk_src.clkr,
+	[SE_GCC_QUPV3_WRAP0_S6_CLK] = &se_gcc_qupv3_wrap0_s6_clk.clkr,
+	[SE_GCC_QUPV3_WRAP0_S6_CLK_SRC] = &se_gcc_qupv3_wrap0_s6_clk_src.clkr,
+	[SE_GCC_QUPV3_WRAP0_S_AHB_CLK] = &se_gcc_qupv3_wrap0_s_ahb_clk.clkr,
+	[SE_GCC_QUPV3_WRAP1_CORE_2X_CLK] = &se_gcc_qupv3_wrap1_core_2x_clk.clkr,
+	[SE_GCC_QUPV3_WRAP1_CORE_CLK] = &se_gcc_qupv3_wrap1_core_clk.clkr,
+	[SE_GCC_QUPV3_WRAP1_M_AHB_CLK] = &se_gcc_qupv3_wrap1_m_ahb_clk.clkr,
+	[SE_GCC_QUPV3_WRAP1_S0_CLK] = &se_gcc_qupv3_wrap1_s0_clk.clkr,
+	[SE_GCC_QUPV3_WRAP1_S0_CLK_SRC] = &se_gcc_qupv3_wrap1_s0_clk_src.clkr,
+	[SE_GCC_QUPV3_WRAP1_S1_CLK] = &se_gcc_qupv3_wrap1_s1_clk.clkr,
+	[SE_GCC_QUPV3_WRAP1_S1_CLK_SRC] = &se_gcc_qupv3_wrap1_s1_clk_src.clkr,
+	[SE_GCC_QUPV3_WRAP1_S2_CLK] = &se_gcc_qupv3_wrap1_s2_clk.clkr,
+	[SE_GCC_QUPV3_WRAP1_S2_CLK_SRC] = &se_gcc_qupv3_wrap1_s2_clk_src.clkr,
+	[SE_GCC_QUPV3_WRAP1_S3_CLK] = &se_gcc_qupv3_wrap1_s3_clk.clkr,
+	[SE_GCC_QUPV3_WRAP1_S3_CLK_SRC] = &se_gcc_qupv3_wrap1_s3_clk_src.clkr,
+	[SE_GCC_QUPV3_WRAP1_S4_CLK] = &se_gcc_qupv3_wrap1_s4_clk.clkr,
+	[SE_GCC_QUPV3_WRAP1_S4_CLK_SRC] = &se_gcc_qupv3_wrap1_s4_clk_src.clkr,
+	[SE_GCC_QUPV3_WRAP1_S5_CLK] = &se_gcc_qupv3_wrap1_s5_clk.clkr,
+	[SE_GCC_QUPV3_WRAP1_S5_CLK_SRC] = &se_gcc_qupv3_wrap1_s5_clk_src.clkr,
+	[SE_GCC_QUPV3_WRAP1_S6_CLK] = &se_gcc_qupv3_wrap1_s6_clk.clkr,
+	[SE_GCC_QUPV3_WRAP1_S6_CLK_SRC] = &se_gcc_qupv3_wrap1_s6_clk_src.clkr,
+	[SE_GCC_QUPV3_WRAP1_S_AHB_CLK] = &se_gcc_qupv3_wrap1_s_ahb_clk.clkr,
+};
+
+static struct gdsc *se_gcc_nord_gdscs[] = {
+	[SE_GCC_EMAC0_GDSC] = &se_gcc_emac0_gdsc,
+	[SE_GCC_EMAC1_GDSC] = &se_gcc_emac1_gdsc,
+};
+
+static const struct qcom_reset_map se_gcc_nord_resets[] = {
+	[SE_GCC_EMAC0_BCR] = { 0x24000 },
+	[SE_GCC_EMAC1_BCR] = { 0x25000 },
+	[SE_GCC_QUPV3_WRAPPER_0_BCR] = { 0x26000 },
+	[SE_GCC_QUPV3_WRAPPER_1_BCR] = { 0x27000 },
+};
+
+static const struct clk_rcg_dfs_data se_gcc_nord_dfs_clocks[] = {
+	DEFINE_RCG_DFS(se_gcc_qupv3_wrap0_s0_clk_src),
+	DEFINE_RCG_DFS(se_gcc_qupv3_wrap0_s1_clk_src),
+	DEFINE_RCG_DFS(se_gcc_qupv3_wrap0_s2_clk_src),
+	DEFINE_RCG_DFS(se_gcc_qupv3_wrap0_s3_clk_src),
+	DEFINE_RCG_DFS(se_gcc_qupv3_wrap0_s4_clk_src),
+	DEFINE_RCG_DFS(se_gcc_qupv3_wrap0_s5_clk_src),
+	DEFINE_RCG_DFS(se_gcc_qupv3_wrap0_s6_clk_src),
+	DEFINE_RCG_DFS(se_gcc_qupv3_wrap1_s0_clk_src),
+	DEFINE_RCG_DFS(se_gcc_qupv3_wrap1_s1_clk_src),
+	DEFINE_RCG_DFS(se_gcc_qupv3_wrap1_s2_clk_src),
+	DEFINE_RCG_DFS(se_gcc_qupv3_wrap1_s3_clk_src),
+	DEFINE_RCG_DFS(se_gcc_qupv3_wrap1_s4_clk_src),
+	DEFINE_RCG_DFS(se_gcc_qupv3_wrap1_s5_clk_src),
+	DEFINE_RCG_DFS(se_gcc_qupv3_wrap1_s6_clk_src),
+};
+
+static const struct regmap_config se_gcc_nord_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.max_register = 0xf41f0,
+	.fast_io = true,
+};
+
+static struct qcom_cc_driver_data se_gcc_nord_driver_data = {
+	.dfs_rcgs = se_gcc_nord_dfs_clocks,
+	.num_dfs_rcgs = ARRAY_SIZE(se_gcc_nord_dfs_clocks),
+};
+
+static const struct qcom_cc_desc se_gcc_nord_desc = {
+	.config = &se_gcc_nord_regmap_config,
+	.clks = se_gcc_nord_clocks,
+	.num_clks = ARRAY_SIZE(se_gcc_nord_clocks),
+	.resets = se_gcc_nord_resets,
+	.num_resets = ARRAY_SIZE(se_gcc_nord_resets),
+	.gdscs = se_gcc_nord_gdscs,
+	.num_gdscs = ARRAY_SIZE(se_gcc_nord_gdscs),
+	.driver_data = &se_gcc_nord_driver_data,
+};
+
+static const struct of_device_id se_gcc_nord_match_table[] = {
+	{ .compatible = "qcom,nord-segcc" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, se_gcc_nord_match_table);
+
+static int se_gcc_nord_probe(struct platform_device *pdev)
+{
+	return qcom_cc_probe(pdev, &se_gcc_nord_desc);
+}
+
+static struct platform_driver se_gcc_nord_driver = {
+	.probe = se_gcc_nord_probe,
+	.driver = {
+		.name = "segcc-nord",
+		.of_match_table = se_gcc_nord_match_table,
+	},
+};
+
+module_platform_driver(se_gcc_nord_driver);
+
+MODULE_DESCRIPTION("QTI SEGCC NORD Driver");
+MODULE_LICENSE("GPL");

-- 
2.47.3


^ permalink raw reply related

* [PATCH 7/7] arm64: defconfig: enable clock controller drivers for Qualcomm Nord
From: Bartosz Golaszewski @ 2026-04-03 14:10 UTC (permalink / raw)
  To: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Taniya Das, Taniya Das,
	Richard Cochran, Shawn Guo, Deepti Jaggi
  Cc: linux-arm-msm, linux-clk, devicetree, linux-kernel, netdev,
	Bartosz Golaszewski
In-Reply-To: <20260403-nord-clks-v1-0-018af14979fd@oss.qualcomm.com>

Enable the clock controller drivers for Nord platform from Qualcomm.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
 arch/arm64/configs/defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 163b7f0314c90fc45eb6c4aa5e8faa549c60fdf7..f1a3333bb07482ef4f8b4ea9154b0f2c74587a04 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -1483,6 +1483,8 @@ CONFIG_CLK_KAANAPALI_GCC=y
 CONFIG_CLK_KAANAPALI_GPUCC=m
 CONFIG_CLK_KAANAPALI_TCSRCC=m
 CONFIG_CLK_KAANAPALI_VIDEOCC=m
+CONFIG_CLK_NORD_GCC=y
+CONFIG_CLK_NORD_TCSRCC=y
 CONFIG_CLK_X1E80100_CAMCC=m
 CONFIG_CLK_X1E80100_DISPCC=m
 CONFIG_CLK_X1E80100_GCC=y

-- 
2.47.3


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox