feat(nxp-clk): refactor clock enablement
Simplify the clock enablement mechanism from a usage perspective. With
this new approach, enabling a clock cascades the turn-on sequence of all
its parent clocks in the clock tree. Therefore, enabling the A53 clock
will also turn on the A53 PLL and the oscillator that feeds it.
Change-Id: Ifc2bee3e9edbb4baced34f9e809a961562f7d0a6
Signed-off-by: Ghennadi Procopciuc <ghennadi.procopciuc@nxp.com>
diff --git a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
index 5018e59..14b03d9 100644
--- a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
+++ b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c
@@ -14,7 +14,7 @@
#include <s32cc-clk-modules.h>
#include <s32cc-clk-utils.h>
-#define MAX_STACK_DEPTH (15U)
+#define MAX_STACK_DEPTH (40U)
/* This is used for floating-point precision calculations. */
#define FP_PRECISION (100000000UL)
@@ -52,7 +52,9 @@
return &driver;
}
-static int enable_module(const struct s32cc_clk_obj *module, unsigned int *depth);
+static int enable_module(struct s32cc_clk_obj *module,
+ const struct s32cc_clk_drv *drv,
+ unsigned int depth);
static struct s32cc_clk_obj *get_clk_parent(const struct s32cc_clk_obj *module)
{
@@ -69,33 +71,6 @@
return NULL;
}
-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 int get_base_addr(enum s32cc_clk_source id, const struct s32cc_clk_drv *drv,
uintptr_t *base)
{
@@ -160,14 +135,14 @@
}
}
-static int enable_osc(const struct s32cc_clk_obj *module,
+static int enable_osc(struct s32cc_clk_obj *module,
const struct s32cc_clk_drv *drv,
- unsigned int *depth)
+ unsigned int depth)
{
const struct s32cc_osc *osc = s32cc_obj2osc(module);
int ret = 0;
- ret = update_stack_depth(depth);
+ ret = update_stack_depth(&depth);
if (ret != 0) {
return ret;
}
@@ -339,9 +314,9 @@
return ret;
}
-static int enable_pll(const struct s32cc_clk_obj *module,
+static int enable_pll(struct s32cc_clk_obj *module,
const struct s32cc_clk_drv *drv,
- unsigned int *depth)
+ unsigned int depth)
{
const struct s32cc_pll *pll = s32cc_obj2pll(module);
const struct s32cc_clkmux *mux;
@@ -350,7 +325,7 @@
uint32_t sclk_id;
int ret;
- ret = update_stack_depth(depth);
+ ret = update_stack_depth(&depth);
if (ret != 0) {
return ret;
}
@@ -440,9 +415,9 @@
return pdiv->parent;
}
-static int enable_pll_div(const struct s32cc_clk_obj *module,
+static int enable_pll_div(struct s32cc_clk_obj *module,
const struct s32cc_clk_drv *drv,
- unsigned int *depth)
+ unsigned int depth)
{
const struct s32cc_pll_out_div *pdiv = s32cc_obj2plldiv(module);
uintptr_t pll_addr = 0x0ULL;
@@ -450,7 +425,7 @@
uint32_t dc;
int ret;
- ret = update_stack_depth(depth);
+ ret = update_stack_depth(&depth);
if (ret != 0) {
return ret;
}
@@ -582,15 +557,15 @@
return &clk->desc;
}
-static int enable_mux(const struct s32cc_clk_obj *module,
+static int enable_mux(struct s32cc_clk_obj *module,
const struct s32cc_clk_drv *drv,
- unsigned int *depth)
+ unsigned int depth)
{
const struct s32cc_clkmux *mux = s32cc_obj2clkmux(module);
const struct s32cc_clk *clk;
int ret = 0;
- ret = update_stack_depth(depth);
+ ret = update_stack_depth(&depth);
if (ret != 0) {
return ret;
}
@@ -637,13 +612,13 @@
return dfs->parent;
}
-static int enable_dfs(const struct s32cc_clk_obj *module,
+static int enable_dfs(struct s32cc_clk_obj *module,
const struct s32cc_clk_drv *drv,
- unsigned int *depth)
+ unsigned int depth)
{
int ret = 0;
- ret = update_stack_depth(depth);
+ ret = update_stack_depth(&depth);
if (ret != 0) {
return ret;
}
@@ -802,9 +777,9 @@
return dfs_div->parent;
}
-static int enable_dfs_div(const struct s32cc_clk_obj *module,
+static int enable_dfs_div(struct s32cc_clk_obj *module,
const struct s32cc_clk_drv *drv,
- unsigned int *depth)
+ unsigned int depth)
{
const struct s32cc_dfs_div *dfs_div = s32cc_obj2dfsdiv(module);
const struct s32cc_pll *pll;
@@ -813,7 +788,7 @@
uint32_t mfi, mfn;
int ret = 0;
- ret = update_stack_depth(depth);
+ ret = update_stack_depth(&depth);
if (ret != 0) {
return ret;
}
@@ -842,12 +817,69 @@
return init_dfs_port(dfs_addr, dfs_div->index, mfi, mfn);
}
-static int enable_module(const struct s32cc_clk_obj *module, unsigned int *depth)
+typedef int (*enable_clk_t)(struct s32cc_clk_obj *module,
+ const struct s32cc_clk_drv *drv,
+ unsigned int depth);
+
+static int no_enable(struct s32cc_clk_obj *module,
+ const struct s32cc_clk_drv *drv,
+ unsigned int depth)
{
- const struct s32cc_clk_drv *drv = get_drv();
+ return 0;
+}
+
+static int exec_cb_with_refcount(enable_clk_t en_cb, struct s32cc_clk_obj *mod,
+ const struct s32cc_clk_drv *drv, bool leaf_node,
+ unsigned int depth)
+{
+ int ret = 0;
+
+ if (mod == NULL) {
+ return 0;
+ }
+
+ ret = update_stack_depth(&depth);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Refcount will be updated as part of the recursivity */
+ if (leaf_node) {
+ return en_cb(mod, drv, depth);
+ }
+
+ if (mod->refcount == 0U) {
+ ret = en_cb(mod, drv, depth);
+ }
+
+ if (ret == 0) {
+ mod->refcount++;
+ }
+
+ return ret;
+}
+
+static struct s32cc_clk_obj *get_module_parent(const struct s32cc_clk_obj *module);
+
+static int enable_module(struct s32cc_clk_obj *module,
+ const struct s32cc_clk_drv *drv,
+ unsigned int depth)
+{
+ struct s32cc_clk_obj *parent = get_module_parent(module);
+ static const enable_clk_t enable_clbs[8] = {
+ [s32cc_clk_t] = no_enable,
+ [s32cc_osc_t] = enable_osc,
+ [s32cc_pll_t] = enable_pll,
+ [s32cc_pll_out_div_t] = enable_pll_div,
+ [s32cc_clkmux_t] = enable_mux,
+ [s32cc_shared_clkmux_t] = enable_mux,
+ [s32cc_dfs_t] = enable_dfs,
+ [s32cc_dfs_div_t] = enable_dfs_div,
+ };
+ uint32_t index;
int ret = 0;
- ret = update_stack_depth(depth);
+ ret = update_stack_depth(&depth);
if (ret != 0) {
return ret;
}
@@ -856,53 +888,55 @@
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_pll_t:
- ret = enable_pll(module, drv, depth);
- break;
- case s32cc_pll_out_div_t:
- ret = enable_pll_div(module, drv, depth);
- break;
- case s32cc_clkmux_t:
- ret = enable_mux(module, drv, depth);
- break;
- case s32cc_shared_clkmux_t:
- ret = enable_mux(module, drv, depth);
- break;
- case s32cc_fixed_div_t:
- ret = -ENOTSUP;
- break;
- case s32cc_dfs_t:
- ret = enable_dfs(module, drv, depth);
- break;
- case s32cc_dfs_div_t:
- ret = enable_dfs_div(module, drv, depth);
- break;
- default:
- ret = -EINVAL;
- break;
+ index = (uint32_t)module->type;
+
+ if (index >= ARRAY_SIZE(enable_clbs)) {
+ ERROR("Undefined module type: %d\n", module->type);
+ return -EINVAL;
+ }
+
+ if (enable_clbs[index] == NULL) {
+ ERROR("Undefined callback for the clock type: %d\n",
+ module->type);
+ return -EINVAL;
+ }
+
+ parent = get_module_parent(module);
+
+ ret = exec_cb_with_refcount(enable_module, parent, drv,
+ false, depth);
+ if (ret != 0) {
+ return ret;
}
+ ret = exec_cb_with_refcount(enable_clbs[index], module, drv,
+ true, depth);
+ if (ret != 0) {
+ return ret;
+ }
+
return ret;
}
+static int enable_module_with_refcount(struct s32cc_clk_obj *module,
+ const struct s32cc_clk_drv *drv,
+ unsigned int depth)
+{
+ return exec_cb_with_refcount(enable_module, module, drv, false, depth);
+}
+
static int s32cc_clk_enable(unsigned long id)
{
+ const struct s32cc_clk_drv *drv = get_drv();
unsigned int depth = MAX_STACK_DEPTH;
- const struct s32cc_clk *clk;
+ struct s32cc_clk *clk;
clk = s32cc_get_arch_clk(id);
if (clk == NULL) {
return -EINVAL;
}
- return enable_module(&clk->desc, &depth);
+ return enable_module_with_refcount(&clk->desc, drv, 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 8c4a9e8..3f6d3d7 100644
--- a/drivers/nxp/clk/s32cc/s32cc_early_clks.c
+++ b/drivers/nxp/clk/s32cc/s32cc_early_clks.c
@@ -17,7 +17,7 @@
#define S32CC_PERIPH_PLL_VCO_FREQ (2U * GHZ)
#define S32CC_PERIPH_PLL_PHI3_FREQ UART_CLOCK_HZ
-static int enable_fxosc_clk(void)
+static int setup_fxosc(void)
{
int ret;
@@ -26,15 +26,10 @@
return ret;
}
- ret = clk_enable(S32CC_CLK_FXOSC);
- if (ret != 0) {
- return ret;
- }
-
return ret;
}
-static int enable_arm_pll(void)
+static int setup_arm_pll(void)
{
int ret;
@@ -53,20 +48,10 @@
return ret;
}
- ret = clk_enable(S32CC_CLK_ARM_PLL_VCO);
- if (ret != 0) {
- return ret;
- }
-
- ret = clk_enable(S32CC_CLK_ARM_PLL_PHI0);
- if (ret != 0) {
- return ret;
- }
-
return ret;
}
-static int enable_periph_pll(void)
+static int setup_periph_pll(void)
{
int ret;
@@ -85,16 +70,6 @@
return ret;
}
- ret = clk_enable(S32CC_CLK_PERIPH_PLL_VCO);
- if (ret != 0) {
- return ret;
- }
-
- ret = clk_enable(S32CC_CLK_PERIPH_PLL_PHI3);
- if (ret != 0) {
- return ret;
- }
-
return ret;
}
@@ -170,27 +145,27 @@
s32cc_clk_register_drv();
- ret = enable_fxosc_clk();
+ ret = setup_fxosc();
if (ret != 0) {
return ret;
}
- ret = enable_arm_pll();
+ ret = setup_arm_pll();
if (ret != 0) {
return ret;
}
- ret = enable_periph_pll();
+ ret = enable_a53_clk();
if (ret != 0) {
return ret;
}
- ret = enable_a53_clk();
+ ret = enable_xbar_clk();
if (ret != 0) {
return ret;
}
- ret = enable_xbar_clk();
+ ret = setup_periph_pll();
if (ret != 0) {
return ret;
}