feat(nxp-clk): add FXOSC clock enablement
Add the low-level implementation to enable the FXOSC oscillator, which
is disabled by default when booting the SoC. It will be used by PLLs,
for which support will be added later.
Change-Id: Ie784e4e29b8b4453b39d37594c311af940bebf92
Signed-off-by: Ghennadi Procopciuc <ghennadi.procopciuc@nxp.com>
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..c331a82 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,138 @@
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;
+ 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)
diff --git a/drivers/nxp/clk/s32cc/s32cc_early_clks.c b/drivers/nxp/clk/s32cc/s32cc_early_clks.c
index fc1dc02..8e4e78b 100644
--- a/drivers/nxp/clk/s32cc/s32cc_early_clks.c
+++ b/drivers/nxp/clk/s32cc/s32cc_early_clks.c
@@ -21,5 +21,10 @@
return ret;
}
+ ret = clk_enable(S32CC_CLK_FXOSC);
+ if (ret != 0) {
+ return ret;
+ }
+
return ret;
}