Merge changes from topic "add_s32cc_fxosc_clk" into integration

* changes:
  feat(s32g274a): enable BL2 early clocks
  feat(nxp-clk): implement set_rate for oscillators
  feat(nxp-clk): add oscillator clock objects
  feat(nxp-clk): add minimal set of S32CC clock ids
diff --git a/drivers/nxp/clk/s32cc/s32cc_clk.mk b/drivers/nxp/clk/s32cc/s32cc_clk.mk
index d1f940a..f5279d3 100644
--- a/drivers/nxp/clk/s32cc/s32cc_clk.mk
+++ b/drivers/nxp/clk/s32cc/s32cc_clk.mk
@@ -4,8 +4,15 @@
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
+PLAT_INCLUDES		+= \
+	-I${PLAT_DRIVERS_INCLUDE_PATH}/clk/s32cc \
+
 CLK_SOURCES		:= \
 	${PLAT_DRIVERS_PATH}/clk/s32cc/s32cc_clk_drv.c \
+	${PLAT_DRIVERS_PATH}/clk/s32cc/s32cc_clk_modules.c \
+	${PLAT_DRIVERS_PATH}/clk/s32cc/s32cc_clk_utils.c \
+	${PLAT_DRIVERS_PATH}/clk/s32cc/s32cc_early_clks.c \
+	drivers/clk/clk.c \
 
 ifeq (${BL_COMM_CLK_NEEDED},yes)
 BL2_SOURCES		+= ${CLK_SOURCES}
diff --git a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
index 8453000..e6653bd 100644
--- a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
+++ b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
@@ -5,7 +5,22 @@
  */
 #include <errno.h>
 
+#include <common/debug.h>
 #include <drivers/clk.h>
+#include <s32cc-clk-modules.h>
+#include <s32cc-clk-utils.h>
+
+#define MAX_STACK_DEPTH		(15U)
+
+static int update_stack_depth(unsigned int *depth)
+{
+	if (*depth == 0U) {
+		return -ENOMEM;
+	}
+
+	(*depth)--;
+	return 0;
+}
 
 static int s32cc_clk_enable(unsigned long id)
 {
@@ -26,10 +41,107 @@
 	return 0;
 }
 
+static int set_module_rate(const struct s32cc_clk_obj *module,
+			   unsigned long rate, unsigned long *orate,
+			   unsigned int *depth);
+
+static int set_osc_freq(const struct s32cc_clk_obj *module, unsigned long rate,
+			unsigned long *orate, unsigned int *depth)
+{
+	struct s32cc_osc *osc = s32cc_obj2osc(module);
+	int ret;
+
+	ret = update_stack_depth(depth);
+	if (ret != 0) {
+		return ret;
+	}
+
+	if ((osc->freq != 0UL) && (rate != osc->freq)) {
+		ERROR("Already initialized oscillator. freq = %lu\n",
+		      osc->freq);
+		return -EINVAL;
+	}
+
+	osc->freq = rate;
+	*orate = osc->freq;
+
+	return 0;
+}
+
+static int set_clk_freq(const struct s32cc_clk_obj *module, unsigned long rate,
+			unsigned long *orate, unsigned int *depth)
+{
+	const struct s32cc_clk *clk = s32cc_obj2clk(module);
+	int ret;
+
+	ret = update_stack_depth(depth);
+	if (ret != 0) {
+		return ret;
+	}
+
+	if ((clk->min_freq != 0UL) && (clk->max_freq != 0UL) &&
+	    ((rate < clk->min_freq) || (rate > clk->max_freq))) {
+		ERROR("%lu frequency is out of the allowed range: [%lu:%lu]\n",
+		      rate, clk->min_freq, clk->max_freq);
+		return -EINVAL;
+	}
+
+	if (clk->module != NULL) {
+		return set_module_rate(clk->module, rate, orate, depth);
+	}
+
+	if (clk->pclock != NULL) {
+		return set_clk_freq(&clk->pclock->desc, rate, orate, depth);
+	}
+
+	return -EINVAL;
+}
+
+static int set_module_rate(const struct s32cc_clk_obj *module,
+			   unsigned long rate, unsigned long *orate,
+			   unsigned int *depth)
+{
+	int ret = 0;
+
+	ret = update_stack_depth(depth);
+	if (ret != 0) {
+		return ret;
+	}
+
+	switch (module->type) {
+	case s32cc_clk_t:
+		ret = set_clk_freq(module, rate, orate, depth);
+		break;
+	case s32cc_osc_t:
+		ret = set_osc_freq(module, rate, orate, depth);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
 static int s32cc_clk_set_rate(unsigned long id, unsigned long rate,
 			      unsigned long *orate)
 {
-	return -ENOTSUP;
+	unsigned int depth = MAX_STACK_DEPTH;
+	const struct s32cc_clk *clk;
+	int ret;
+
+	clk = s32cc_get_arch_clk(id);
+	if (clk == NULL) {
+		return -EINVAL;
+	}
+
+	ret = set_module_rate(&clk->desc, rate, orate, &depth);
+	if (ret != 0) {
+		ERROR("Failed to set frequency (%lu MHz) for clock %lu\n",
+		      rate, id);
+	}
+
+	return ret;
 }
 
 static int s32cc_clk_get_parent(unsigned long id)
diff --git a/drivers/nxp/clk/s32cc/s32cc_clk_modules.c b/drivers/nxp/clk/s32cc/s32cc_clk_modules.c
new file mode 100644
index 0000000..f8fc52f
--- /dev/null
+++ b/drivers/nxp/clk/s32cc/s32cc_clk_modules.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2020-2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <s32cc-clk-ids.h>
+#include <s32cc-clk-modules.h>
+#include <s32cc-clk-utils.h>
+
+/* Oscillators */
+static struct s32cc_osc fxosc =
+	S32CC_OSC_INIT(S32CC_FXOSC);
+static struct s32cc_clk fxosc_clk =
+	S32CC_MODULE_CLK(fxosc);
+
+static struct s32cc_osc firc =
+	S32CC_OSC_INIT(S32CC_FIRC);
+static struct s32cc_clk firc_clk =
+	S32CC_MODULE_CLK(firc);
+
+static struct s32cc_osc sirc =
+	S32CC_OSC_INIT(S32CC_SIRC);
+static struct s32cc_clk sirc_clk =
+	S32CC_MODULE_CLK(sirc);
+
+static struct s32cc_clk *s32cc_hw_clk_list[3] = {
+	/* Oscillators */
+	[S32CC_CLK_ID(S32CC_CLK_FIRC)] = &firc_clk,
+	[S32CC_CLK_ID(S32CC_CLK_SIRC)] = &sirc_clk,
+	[S32CC_CLK_ID(S32CC_CLK_FXOSC)] = &fxosc_clk,
+};
+
+static struct s32cc_clk_array s32cc_hw_clocks = {
+	.type_mask = S32CC_CLK_TYPE(S32CC_CLK_FIRC),
+	.clks = &s32cc_hw_clk_list[0],
+	.n_clks = ARRAY_SIZE(s32cc_hw_clk_list),
+};
+
+struct s32cc_clk *s32cc_get_arch_clk(unsigned long id)
+{
+	static const struct s32cc_clk_array *clk_table[1] = {
+		&s32cc_hw_clocks,
+	};
+
+	return s32cc_get_clk_from_table(clk_table, ARRAY_SIZE(clk_table), id);
+}
diff --git a/drivers/nxp/clk/s32cc/s32cc_clk_utils.c b/drivers/nxp/clk/s32cc/s32cc_clk_utils.c
new file mode 100644
index 0000000..14ab674
--- /dev/null
+++ b/drivers/nxp/clk/s32cc/s32cc_clk_utils.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <s32cc-clk-ids.h>
+#include <s32cc-clk-utils.h>
+
+static struct s32cc_clk *s32cc_clk_get_from_array(const struct s32cc_clk_array *arr,
+						  unsigned long clk_id)
+{
+	unsigned long type, id;
+
+	type = S32CC_CLK_TYPE(clk_id);
+
+	if (type != arr->type_mask) {
+		return NULL;
+	}
+
+	id = S32CC_CLK_ID(clk_id);
+
+	if (id >= arr->n_clks) {
+		return NULL;
+	}
+
+	return arr->clks[id];
+}
+
+struct s32cc_clk *s32cc_get_clk_from_table(const struct s32cc_clk_array *const *clk_arr,
+					   size_t size,
+					   unsigned long clk_id)
+{
+	struct s32cc_clk *clk;
+	size_t i;
+
+	for (i = 0; i < size; i++) {
+		clk = s32cc_clk_get_from_array(clk_arr[i], clk_id);
+		if (clk != NULL) {
+			return clk;
+		}
+	}
+
+	return NULL;
+}
diff --git a/drivers/nxp/clk/s32cc/s32cc_early_clks.c b/drivers/nxp/clk/s32cc/s32cc_early_clks.c
new file mode 100644
index 0000000..fc1dc02
--- /dev/null
+++ b/drivers/nxp/clk/s32cc/s32cc_early_clks.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <drivers/clk.h>
+#include <s32cc-clk-drv.h>
+#include <s32cc-clk-ids.h>
+#include <s32cc-clk-utils.h>
+
+#define S32CC_FXOSC_FREQ	(40U * MHZ)
+
+int s32cc_init_early_clks(void)
+{
+	int ret;
+
+	s32cc_clk_register_drv();
+
+	ret = clk_set_rate(S32CC_CLK_FXOSC, S32CC_FXOSC_FREQ, NULL);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return ret;
+}
diff --git a/include/drivers/nxp/clk/s32cc/s32cc-clk-drv.h b/include/drivers/nxp/clk/s32cc/s32cc-clk-drv.h
new file mode 100644
index 0000000..d879f5b
--- /dev/null
+++ b/include/drivers/nxp/clk/s32cc/s32cc-clk-drv.h
@@ -0,0 +1,11 @@
+/*
+ * Copyright 2024 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef S32CC_CLK_DRV_H
+#define S32CC_CLK_DRV_H
+
+int s32cc_init_early_clks(void);
+
+#endif
diff --git a/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h b/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h
new file mode 100644
index 0000000..633f173
--- /dev/null
+++ b/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright 2024 NXP
+ */
+#ifndef S32CC_CLK_IDS_H
+#define S32CC_CLK_IDS_H
+
+#include <stdint.h>
+#include <lib/utils_def.h>
+
+/**
+ * Clock ID encoding:
+ *     31:30 bits = Type of the clock
+ *     29:0  bits = Clock ID within the clock category
+ */
+#define S32CC_CLK_ID_MASK	GENMASK_64(29U, 0U)
+#define S32CC_CLK_TYPE_MASK	GENMASK_64(31U, 30U)
+#define S32CC_CLK_ID(ID)	(((unsigned long)(ID)) & S32CC_CLK_ID_MASK)
+#define S32CC_CLK_TYPE(ID)	(((unsigned long)(ID)) & S32CC_CLK_TYPE_MASK)
+#define S32CC_CLK(TAG, ID)	(S32CC_CLK_ID(ID) | (S32CC_CLK_TYPE((TAG) << 30U)))
+#define S32CC_HW_CLK(ID)	S32CC_CLK(0UL, U(ID))
+#define S32CC_SW_CLK(SUB, ID)	S32CC_CLK(2UL | ((SUB) & 1UL), U(ID))
+
+/* SW clocks subcategories */
+#define S32CC_ARCH_CLK(ID)	S32CC_SW_CLK(0UL, ID)
+#define S32CC_PLAT_CLK(ID)	S32CC_SW_CLK(1UL, ID)
+
+/* IDs for clock selectors listed in S32CC Reference Manuals  */
+#define S32CC_CLK_FIRC				S32CC_HW_CLK(0)
+#define S32CC_CLK_SIRC				S32CC_HW_CLK(1)
+#define S32CC_CLK_FXOSC				S32CC_HW_CLK(2)
+#define S32CC_CLK_ARM_PLL_PHI0			S32CC_HW_CLK(4)
+#define S32CC_CLK_ARM_PLL_PHI1			S32CC_HW_CLK(5)
+#define S32CC_CLK_ARM_PLL_PHI2			S32CC_HW_CLK(6)
+#define S32CC_CLK_ARM_PLL_PHI3			S32CC_HW_CLK(7)
+#define S32CC_CLK_ARM_PLL_PHI4			S32CC_HW_CLK(8)
+#define S32CC_CLK_ARM_PLL_PHI5			S32CC_HW_CLK(9)
+#define S32CC_CLK_ARM_PLL_PHI6			S32CC_HW_CLK(10)
+#define S32CC_CLK_ARM_PLL_PHI7			S32CC_HW_CLK(11)
+#define S32CC_CLK_ARM_PLL_DFS1			S32CC_HW_CLK(12)
+#define S32CC_CLK_ARM_PLL_DFS2			S32CC_HW_CLK(13)
+#define S32CC_CLK_ARM_PLL_DFS3			S32CC_HW_CLK(14)
+#define S32CC_CLK_ARM_PLL_DFS4			S32CC_HW_CLK(15)
+#define S32CC_CLK_ARM_PLL_DFS5			S32CC_HW_CLK(16)
+#define S32CC_CLK_ARM_PLL_DFS6			S32CC_HW_CLK(17)
+#define S32CC_CLK_PERIPH_PLL_PHI0		S32CC_HW_CLK(18)
+#define S32CC_CLK_PERIPH_PLL_PHI1		S32CC_HW_CLK(19)
+#define S32CC_CLK_PERIPH_PLL_PHI2		S32CC_HW_CLK(20)
+#define S32CC_CLK_PERIPH_PLL_PHI3		S32CC_HW_CLK(21)
+#define S32CC_CLK_PERIPH_PLL_PHI4		S32CC_HW_CLK(22)
+#define S32CC_CLK_PERIPH_PLL_PHI5		S32CC_HW_CLK(23)
+#define S32CC_CLK_PERIPH_PLL_PHI6		S32CC_HW_CLK(24)
+#define S32CC_CLK_PERIPH_PLL_PHI7		S32CC_HW_CLK(25)
+#define S32CC_CLK_PERIPH_PLL_DFS1		S32CC_HW_CLK(26)
+#define S32CC_CLK_PERIPH_PLL_DFS2		S32CC_HW_CLK(27)
+#define S32CC_CLK_PERIPH_PLL_DFS3		S32CC_HW_CLK(28)
+#define S32CC_CLK_PERIPH_PLL_DFS4		S32CC_HW_CLK(29)
+#define S32CC_CLK_PERIPH_PLL_DFS5		S32CC_HW_CLK(30)
+#define S32CC_CLK_PERIPH_PLL_DFS6		S32CC_HW_CLK(31)
+#define S32CC_CLK_FTM0_EXT_REF			S32CC_HW_CLK(34)
+#define S32CC_CLK_FTM1_EXT_REF			S32CC_HW_CLK(35)
+#define S32CC_CLK_DDR_PLL_PHI0			S32CC_HW_CLK(36)
+#define S32CC_CLK_GMAC0_EXT_TX			S32CC_HW_CLK(37)
+#define S32CC_CLK_GMAC0_EXT_RX			S32CC_HW_CLK(38)
+#define S32CC_CLK_GMAC0_EXT_REF			S32CC_HW_CLK(39)
+#define S32CC_CLK_SERDES0_LANE0_TX		S32CC_HW_CLK(40)
+#define S32CC_CLK_SERDES0_LANE0_CDR		S32CC_HW_CLK(41)
+#define S32CC_CLK_GMAC0_EXT_TS			S32CC_HW_CLK(44)
+#define S32CC_CLK_GMAC0_REF_DIV			S32CC_HW_CLK(45)
+
+/* Software defined clock IDs */
+#define S32CC_CLK_ARM_PLL_MUX			S32CC_ARCH_CLK(0)
+#define S32CC_CLK_ARM_PLL_VCO			S32CC_ARCH_CLK(1)
+
+/* ARM CGM1 clocks */
+#define S32CC_CLK_MC_CGM1_MUX0			S32CC_ARCH_CLK(2)
+#define S32CC_CLK_A53_CORE			S32CC_ARCH_CLK(3)
+#define S32CC_CLK_A53_CORE_DIV2			S32CC_ARCH_CLK(4)
+#define S32CC_CLK_A53_CORE_DIV10		S32CC_ARCH_CLK(5)
+
+#endif /* S32CC_CLK_IDS_H */
diff --git a/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h b/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h
new file mode 100644
index 0000000..9524f72
--- /dev/null
+++ b/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright 2020-2024 NXP
+ */
+#ifndef S32CC_CLK_MODULES_H
+#define S32CC_CLK_MODULES_H
+
+#include <inttypes.h>
+#include <stddef.h>
+
+#define MHZ	UL(1000000)
+#define GHZ	(UL(1000) * MHZ)
+
+enum s32cc_clkm_type {
+	s32cc_osc_t,
+	s32cc_clk_t,
+};
+
+enum s32cc_clk_source {
+	S32CC_FIRC,
+	S32CC_FXOSC,
+	S32CC_SIRC,
+};
+
+struct s32cc_clk_obj {
+	enum s32cc_clkm_type type;
+	uint32_t refcount;
+};
+
+struct s32cc_osc {
+	struct s32cc_clk_obj desc;
+	enum s32cc_clk_source source;
+	unsigned long freq;
+	void *base;
+};
+
+#define S32CC_OSC_INIT(SOURCE)       \
+{                                    \
+	.desc = {                    \
+		.type = s32cc_osc_t, \
+	},                           \
+	.source = (SOURCE),          \
+}
+
+struct s32cc_clk {
+	struct s32cc_clk_obj desc;
+	struct s32cc_clk_obj *module;
+	struct s32cc_clk *pclock;
+	unsigned long min_freq;
+	unsigned long max_freq;
+};
+
+struct s32cc_clk_array {
+	unsigned long type_mask;
+	struct s32cc_clk **clks;
+	size_t n_clks;
+};
+
+#define S32CC_FREQ_MODULE(PARENT_MODULE, MIN_F, MAX_F) \
+{                                                      \
+	.desc = {                                      \
+		.type = s32cc_clk_t,                   \
+	},                                             \
+	.module = &(PARENT_MODULE).desc,               \
+	.min_freq = (MIN_F),                           \
+	.max_freq = (MAX_F),                           \
+}
+
+#define S32CC_FREQ_MODULE_CLK(PARENT_MODULE, MIN_F, MAX_F) \
+	S32CC_FREQ_MODULE(PARENT_MODULE, MIN_F, MAX_F)
+
+#define S32CC_MODULE_CLK(PARENT_MODULE) \
+	S32CC_FREQ_MODULE_CLK(PARENT_MODULE, 0, 0)
+
+static inline struct s32cc_osc *s32cc_obj2osc(const struct s32cc_clk_obj *mod)
+{
+	uintptr_t osc_addr;
+
+	osc_addr = ((uintptr_t)mod) - offsetof(struct s32cc_osc, desc);
+	return (struct s32cc_osc *)osc_addr;
+}
+
+static inline struct s32cc_clk *s32cc_obj2clk(const struct s32cc_clk_obj *mod)
+{
+	uintptr_t clk_addr;
+
+	clk_addr = ((uintptr_t)mod) - offsetof(struct s32cc_clk, desc);
+	return (struct s32cc_clk *)clk_addr;
+}
+
+#endif /* S32CC_CLK_MODULES_H */
diff --git a/include/drivers/nxp/clk/s32cc/s32cc-clk-utils.h b/include/drivers/nxp/clk/s32cc/s32cc-clk-utils.h
new file mode 100644
index 0000000..6a90406
--- /dev/null
+++ b/include/drivers/nxp/clk/s32cc/s32cc-clk-utils.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright 2024 NXP
+ */
+#ifndef S32CC_CLK_UTILS_H
+#define S32CC_CLK_UTILS_H
+
+#include <s32cc-clk-modules.h>
+
+struct s32cc_clk *s32cc_get_clk_from_table(const struct s32cc_clk_array *const *clk_arr,
+					   size_t size,
+					   unsigned long clk_id);
+
+struct s32cc_clk *s32cc_get_arch_clk(unsigned long id);
+
+void s32cc_clk_register_drv(void);
+
+#endif /* S32CC_CLK_UTILS_H */
diff --git a/plat/nxp/s32/s32g274ardb2/plat_bl2_el3_setup.c b/plat/nxp/s32/s32g274ardb2/plat_bl2_el3_setup.c
index f265d95..705832c 100644
--- a/plat/nxp/s32/s32g274ardb2/plat_bl2_el3_setup.c
+++ b/plat/nxp/s32/s32g274ardb2/plat_bl2_el3_setup.c
@@ -4,10 +4,12 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <common/debug.h>
 #include <common/desc_image_load.h>
 #include <lib/mmio.h>
 #include <plat/common/platform.h>
 #include <plat_console.h>
+#include <s32cc-clk-drv.h>
 #include <plat_io_storage.h>
 
 #define SIUL2_PC09_MSCR		UL(0x4009C2E4)
@@ -50,6 +52,13 @@
 void bl2_el3_early_platform_setup(u_register_t arg0, u_register_t arg1,
 				  u_register_t arg2, u_register_t arg3)
 {
+	int ret;
+
+	ret = s32cc_init_early_clks();
+	if (ret != 0) {
+		panic();
+	}
+
 	linflex_config_pinctrl();
 	console_s32g2_register();