Merge changes from topic "add_s32cc_pll" into integration

* changes:
  feat(nxp-clk): set parent for ARM PLL and MC_CGM muxes
  feat(nxp-clk): add MC_CGM clock objects
  feat(nxp-clk): add set_parent callback
  feat(nxp-clk): add clock objects for ARM PLL
  feat(nxp-clk): add FXOSC clock enablement
diff --git a/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h b/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h
new file mode 100644
index 0000000..7ae9624
--- /dev/null
+++ b/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright 2020-2021, 2023-2024 NXP
+ */
+#ifndef S32CC_CLK_REGS_H
+#define S32CC_CLK_REGS_H
+
+#include <lib/utils_def.h>
+
+#define FXOSC_BASE_ADDR			(0x40050000UL)
+
+/* FXOSC */
+#define FXOSC_CTRL(FXOSC)		((FXOSC) + 0x0UL)
+#define FXOSC_CTRL_OSC_BYP		BIT_32(31U)
+#define FXOSC_CTRL_COMP_EN		BIT_32(24U)
+#define FXOSC_CTRL_EOCV_OFFSET		16U
+#define FXOSC_CTRL_EOCV_MASK		GENMASK_32(23U, FXOSC_CTRL_EOCV_OFFSET)
+#define FXOSC_CTRL_EOCV(VAL)		(FXOSC_CTRL_EOCV_MASK & \
+					 ((uint32_t)(VAL) << FXOSC_CTRL_EOCV_OFFSET))
+#define FXOSC_CTRL_GM_SEL_OFFSET	4U
+#define FXOSC_CTRL_GM_SEL_MASK		GENMASK_32(7U, FXOSC_CTRL_GM_SEL_OFFSET)
+#define FXOSC_CTRL_GM_SEL(VAL)		(FXOSC_CTRL_GM_SEL_MASK & \
+					 ((uint32_t)(VAL) << FXOSC_CTRL_GM_SEL_OFFSET))
+#define FXOSC_CTRL_OSCON		BIT_32(0U)
+
+#define FXOSC_STAT(FXOSC)		((FXOSC) + 0x4UL)
+#define FXOSC_STAT_OSC_STAT		BIT_32(31U)
+
+#endif /* S32CC_CLK_REGS_H */
diff --git a/drivers/nxp/clk/s32cc/s32cc_clk.mk b/drivers/nxp/clk/s32cc/s32cc_clk.mk
index f5279d3..7a65ea6 100644
--- a/drivers/nxp/clk/s32cc/s32cc_clk.mk
+++ b/drivers/nxp/clk/s32cc/s32cc_clk.mk
@@ -6,6 +6,7 @@
 
 PLAT_INCLUDES		+= \
 	-I${PLAT_DRIVERS_INCLUDE_PATH}/clk/s32cc \
+	-I${PLAT_DRIVERS_PATH}/clk/s32cc/include \
 
 CLK_SOURCES		:= \
 	${PLAT_DRIVERS_PATH}/clk/s32cc/s32cc_clk_drv.c \
diff --git a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
index e6653bd..69a9d21 100644
--- a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
+++ b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
@@ -5,13 +5,20 @@
  */
 #include <errno.h>
 
+#include <s32cc-clk-regs.h>
+
 #include <common/debug.h>
 #include <drivers/clk.h>
+#include <lib/mmio.h>
 #include <s32cc-clk-modules.h>
 #include <s32cc-clk-utils.h>
 
 #define MAX_STACK_DEPTH		(15U)
 
+struct s32cc_clk_drv {
+	uintptr_t fxosc_base;
+};
+
 static int update_stack_depth(unsigned int *depth)
 {
 	if (*depth == 0U) {
@@ -22,9 +29,150 @@
 	return 0;
 }
 
+static struct s32cc_clk_drv *get_drv(void)
+{
+	static struct s32cc_clk_drv driver = {
+		.fxosc_base = FXOSC_BASE_ADDR,
+	};
+
+	return &driver;
+}
+
+static int enable_module(const struct s32cc_clk_obj *module, unsigned int *depth);
+
+static int enable_clk_module(const struct s32cc_clk_obj *module,
+			     const struct s32cc_clk_drv *drv,
+			     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 == NULL) {
+		return -EINVAL;
+	}
+
+	if (clk->module != NULL) {
+		return enable_module(clk->module, depth);
+	}
+
+	if (clk->pclock != NULL) {
+		return enable_clk_module(&clk->pclock->desc, drv, depth);
+	}
+
+	return -EINVAL;
+}
+
+static void enable_fxosc(const struct s32cc_clk_drv *drv)
+{
+	uintptr_t fxosc_base = drv->fxosc_base;
+	uint32_t ctrl;
+
+	ctrl = mmio_read_32(FXOSC_CTRL(fxosc_base));
+	if ((ctrl & FXOSC_CTRL_OSCON) != U(0)) {
+		return;
+	}
+
+	ctrl = FXOSC_CTRL_COMP_EN;
+	ctrl &= ~FXOSC_CTRL_OSC_BYP;
+	ctrl |= FXOSC_CTRL_EOCV(0x1);
+	ctrl |= FXOSC_CTRL_GM_SEL(0x7);
+	mmio_write_32(FXOSC_CTRL(fxosc_base), ctrl);
+
+	/* Switch ON the crystal oscillator. */
+	mmio_setbits_32(FXOSC_CTRL(fxosc_base), FXOSC_CTRL_OSCON);
+
+	/* Wait until the clock is stable. */
+	while ((mmio_read_32(FXOSC_STAT(fxosc_base)) & FXOSC_STAT_OSC_STAT) == U(0)) {
+	}
+}
+
+static int enable_osc(const struct s32cc_clk_obj *module,
+		      const struct s32cc_clk_drv *drv,
+		      unsigned int *depth)
+{
+	const struct s32cc_osc *osc = s32cc_obj2osc(module);
+	int ret = 0;
+
+	ret = update_stack_depth(depth);
+	if (ret != 0) {
+		return ret;
+	}
+
+	switch (osc->source) {
+	case S32CC_FXOSC:
+		enable_fxosc(drv);
+		break;
+	/* FIRC and SIRC oscillators are enabled by default */
+	case S32CC_FIRC:
+		break;
+	case S32CC_SIRC:
+		break;
+	default:
+		ERROR("Invalid oscillator %d\n", osc->source);
+		ret = -EINVAL;
+		break;
+	};
+
+	return ret;
+}
+
+static int enable_module(const struct s32cc_clk_obj *module, unsigned int *depth)
+{
+	const struct s32cc_clk_drv *drv = get_drv();
+	int ret = 0;
+
+	ret = update_stack_depth(depth);
+	if (ret != 0) {
+		return ret;
+	}
+
+	if (drv == NULL) {
+		return -EINVAL;
+	}
+
+	switch (module->type) {
+	case s32cc_osc_t:
+		ret = enable_osc(module, drv, depth);
+		break;
+	case s32cc_clk_t:
+		ret = enable_clk_module(module, drv, depth);
+		break;
+	case s32cc_clkmux_t:
+		ret = -ENOTSUP;
+		break;
+	case s32cc_shared_clkmux_t:
+		ret = -ENOTSUP;
+		break;
+	case s32cc_pll_t:
+		ret = -ENOTSUP;
+		break;
+	case s32cc_pll_out_div_t:
+		ret = -ENOTSUP;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
 static int s32cc_clk_enable(unsigned long id)
 {
-	return -ENOTSUP;
+	unsigned int depth = MAX_STACK_DEPTH;
+	const struct s32cc_clk *clk;
+
+	clk = s32cc_get_arch_clk(id);
+	if (clk == NULL) {
+		return -EINVAL;
+	}
+
+	return enable_module(&clk->desc, &depth);
 }
 
 static void s32cc_clk_disable(unsigned long id)
@@ -115,6 +263,12 @@
 	case s32cc_osc_t:
 		ret = set_osc_freq(module, rate, orate, depth);
 		break;
+	case s32cc_clkmux_t:
+	case s32cc_shared_clkmux_t:
+	case s32cc_pll_t:
+	case s32cc_pll_out_div_t:
+		ret = -ENOTSUP;
+		break;
 	default:
 		ret = -EINVAL;
 		break;
@@ -151,7 +305,49 @@
 
 static int s32cc_clk_set_parent(unsigned long id, unsigned long parent_id)
 {
-	return -ENOTSUP;
+	const struct s32cc_clk *parent;
+	const struct s32cc_clk *clk;
+	bool valid_source = false;
+	struct s32cc_clkmux *mux;
+	uint8_t i;
+
+	clk = s32cc_get_arch_clk(id);
+	if (clk == NULL) {
+		return -EINVAL;
+	}
+
+	parent = s32cc_get_arch_clk(parent_id);
+	if (parent == NULL) {
+		return -EINVAL;
+	}
+
+	if (!is_s32cc_clk_mux(clk)) {
+		ERROR("Clock %lu is not a mux\n", id);
+		return -EINVAL;
+	}
+
+	mux = s32cc_clk2mux(clk);
+	if (mux == NULL) {
+		ERROR("Failed to cast clock %lu to clock mux\n", id);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < mux->nclks; i++) {
+		if (mux->clkids[i] == parent_id) {
+			valid_source = true;
+			break;
+		}
+	}
+
+	if (!valid_source) {
+		ERROR("Clock %lu is not a valid clock for mux %lu\n",
+		      parent_id, id);
+		return -EINVAL;
+	}
+
+	mux->source_id = parent_id;
+
+	return 0;
 }
 
 void s32cc_clk_register_drv(void)
diff --git a/drivers/nxp/clk/s32cc/s32cc_clk_modules.c b/drivers/nxp/clk/s32cc/s32cc_clk_modules.c
index f8fc52f..1f381b6 100644
--- a/drivers/nxp/clk/s32cc/s32cc_clk_modules.c
+++ b/drivers/nxp/clk/s32cc/s32cc_clk_modules.c
@@ -23,11 +23,38 @@
 static struct s32cc_clk sirc_clk =
 	S32CC_MODULE_CLK(sirc);
 
-static struct s32cc_clk *s32cc_hw_clk_list[3] = {
+/* ARM PLL */
+static struct s32cc_clkmux arm_pll_mux =
+	S32CC_CLKMUX_INIT(S32CC_ARM_PLL, 0, 2,
+			  S32CC_CLK_FIRC,
+			  S32CC_CLK_FXOSC, 0, 0, 0);
+static struct s32cc_clk arm_pll_mux_clk =
+	S32CC_MODULE_CLK(arm_pll_mux);
+static struct s32cc_pll armpll =
+	S32CC_PLL_INIT(arm_pll_mux_clk, S32CC_ARM_PLL, 2);
+static struct s32cc_clk arm_pll_vco_clk =
+	S32CC_FREQ_MODULE_CLK(armpll, 1400 * MHZ, 2000 * MHZ);
+
+static struct s32cc_pll_out_div arm_pll_phi0_div =
+	S32CC_PLL_OUT_DIV_INIT(armpll, 0);
+static struct s32cc_clk arm_pll_phi0_clk =
+	S32CC_FREQ_MODULE_CLK(arm_pll_phi0_div, 0, GHZ);
+
+/* MC_CGM1 */
+static struct s32cc_clkmux cgm1_mux0 =
+	S32CC_SHARED_CLKMUX_INIT(S32CC_CGM1, 0, 3,
+				 S32CC_CLK_FIRC,
+				 S32CC_CLK_ARM_PLL_PHI0,
+				 S32CC_CLK_ARM_PLL_DFS2, 0, 0);
+static struct s32cc_clk cgm1_mux0_clk = S32CC_MODULE_CLK(cgm1_mux0);
+
+static struct s32cc_clk *s32cc_hw_clk_list[5] = {
 	/* 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,
+	/* ARM PLL */
+	[S32CC_CLK_ID(S32CC_CLK_ARM_PLL_PHI0)] = &arm_pll_phi0_clk,
 };
 
 static struct s32cc_clk_array s32cc_hw_clocks = {
@@ -36,10 +63,25 @@
 	.n_clks = ARRAY_SIZE(s32cc_hw_clk_list),
 };
 
+static struct s32cc_clk *s32cc_arch_clk_list[3] = {
+	/* ARM PLL */
+	[S32CC_CLK_ID(S32CC_CLK_ARM_PLL_MUX)] = &arm_pll_mux_clk,
+	[S32CC_CLK_ID(S32CC_CLK_ARM_PLL_VCO)] = &arm_pll_vco_clk,
+	/* MC_CGM1 */
+	[S32CC_CLK_ID(S32CC_CLK_MC_CGM1_MUX0)] = &cgm1_mux0_clk,
+};
+
+static struct s32cc_clk_array s32cc_arch_clocks = {
+	.type_mask = S32CC_CLK_TYPE(S32CC_CLK_ARM_PLL_MUX),
+	.clks = &s32cc_arch_clk_list[0],
+	.n_clks = ARRAY_SIZE(s32cc_arch_clk_list),
+};
+
 struct s32cc_clk *s32cc_get_arch_clk(unsigned long id)
 {
-	static const struct s32cc_clk_array *clk_table[1] = {
+	static const struct s32cc_clk_array *clk_table[2] = {
 		&s32cc_hw_clocks,
+		&s32cc_arch_clocks,
 	};
 
 	return s32cc_get_clk_from_table(clk_table, ARRAY_SIZE(clk_table), id);
diff --git a/drivers/nxp/clk/s32cc/s32cc_early_clks.c b/drivers/nxp/clk/s32cc/s32cc_early_clks.c
index fc1dc02..98f30d8 100644
--- a/drivers/nxp/clk/s32cc/s32cc_early_clks.c
+++ b/drivers/nxp/clk/s32cc/s32cc_early_clks.c
@@ -16,10 +16,25 @@
 
 	s32cc_clk_register_drv();
 
+	ret = clk_set_parent(S32CC_CLK_ARM_PLL_MUX, S32CC_CLK_FXOSC);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = clk_set_parent(S32CC_CLK_MC_CGM1_MUX0, S32CC_CLK_ARM_PLL_PHI0);
+	if (ret != 0) {
+		return ret;
+	}
+
 	ret = clk_set_rate(S32CC_CLK_FXOSC, S32CC_FXOSC_FREQ, NULL);
 	if (ret != 0) {
 		return ret;
 	}
 
+	ret = clk_enable(S32CC_CLK_FXOSC);
+	if (ret != 0) {
+		return ret;
+	}
+
 	return ret;
 }
diff --git a/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h b/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h
index 9524f72..6ffe321 100644
--- a/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h
+++ b/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h
@@ -6,6 +6,7 @@
 #define S32CC_CLK_MODULES_H
 
 #include <inttypes.h>
+#include <stdbool.h>
 #include <stddef.h>
 
 #define MHZ	UL(1000000)
@@ -14,12 +15,18 @@
 enum s32cc_clkm_type {
 	s32cc_osc_t,
 	s32cc_clk_t,
+	s32cc_pll_t,
+	s32cc_pll_out_div_t,
+	s32cc_clkmux_t,
+	s32cc_shared_clkmux_t,
 };
 
 enum s32cc_clk_source {
 	S32CC_FIRC,
 	S32CC_FXOSC,
 	S32CC_SIRC,
+	S32CC_ARM_PLL,
+	S32CC_CGM1,
 };
 
 struct s32cc_clk_obj {
@@ -42,6 +49,69 @@
 	.source = (SOURCE),          \
 }
 
+struct s32cc_clkmux {
+	struct s32cc_clk_obj desc;
+	enum s32cc_clk_source module;
+	uint8_t index; /* Mux index in parent module */
+	unsigned long source_id; /* Selected source */
+	uint8_t nclks; /* Number of input clocks */
+	unsigned long clkids[5]; /* IDs of the input clocks */
+};
+
+#define S32CC_CLKMUX_TYPE_INIT(TYPE, MODULE, INDEX, NCLKS, ...) \
+{                                                               \
+	.desc = {                                               \
+		.type = (TYPE),                                 \
+	},                                                      \
+	.module = (MODULE),                                     \
+	.index = (INDEX),                                       \
+	.nclks = (NCLKS),                                       \
+	.clkids = {__VA_ARGS__},                                \
+}
+
+#define S32CC_CLKMUX_INIT(MODULE, INDEX, NCLKS, ...)     \
+	S32CC_CLKMUX_TYPE_INIT(s32cc_clkmux_t, MODULE,   \
+			       INDEX, NCLKS, __VA_ARGS__)
+
+#define S32CC_SHARED_CLKMUX_INIT(MODULE, INDEX, NCLKS, ...)   \
+	S32CC_CLKMUX_TYPE_INIT(s32cc_shared_clkmux_t, MODULE, \
+			       INDEX, NCLKS, __VA_ARGS__)
+
+struct s32cc_pll {
+	struct s32cc_clk_obj desc;
+	struct s32cc_clk_obj *source;
+	enum s32cc_clk_source instance;
+	unsigned long vco_freq;
+	uint32_t ndividers;
+	uintptr_t base;
+};
+
+#define S32CC_PLL_INIT(PLL_MUX_CLK, INSTANCE, NDIVIDERS) \
+{                                                        \
+	.desc = {                                        \
+		.type = s32cc_pll_t,                     \
+	},                                               \
+	.source = &(PLL_MUX_CLK).desc,                   \
+	.instance = (INSTANCE),                          \
+	.ndividers = (NDIVIDERS),                        \
+}
+
+struct s32cc_pll_out_div {
+	struct s32cc_clk_obj desc;
+	struct s32cc_clk_obj *parent;
+	uint32_t index;
+	unsigned long freq;
+};
+
+#define S32CC_PLL_OUT_DIV_INIT(PARENT, INDEX)  \
+{                                              \
+	.desc = {                              \
+		.type = s32cc_pll_out_div_t,   \
+	},                                     \
+	.parent = &(PARENT).desc,              \
+	.index = (INDEX),                      \
+}
+
 struct s32cc_clk {
 	struct s32cc_clk_obj desc;
 	struct s32cc_clk_obj *module;
@@ -88,4 +158,34 @@
 	return (struct s32cc_clk *)clk_addr;
 }
 
+static inline bool is_s32cc_clk_mux(const struct s32cc_clk *clk)
+{
+	const struct s32cc_clk_obj *module;
+
+	module = clk->module;
+	if (module == NULL) {
+		return false;
+	}
+
+	return (module->type == s32cc_clkmux_t) ||
+	    (module->type == s32cc_shared_clkmux_t);
+}
+
+static inline struct s32cc_clkmux *s32cc_obj2clkmux(const struct s32cc_clk_obj *mod)
+{
+	uintptr_t cmux_addr;
+
+	cmux_addr = ((uintptr_t)mod) - offsetof(struct s32cc_clkmux, desc);
+	return (struct s32cc_clkmux *)cmux_addr;
+}
+
+static inline struct s32cc_clkmux *s32cc_clk2mux(const struct s32cc_clk *clk)
+{
+	if (!is_s32cc_clk_mux(clk)) {
+		return NULL;
+	}
+
+	return s32cc_obj2clkmux(clk->module);
+}
+
 #endif /* S32CC_CLK_MODULES_H */