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 */