Browse Source

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
pull/1996/merge
Madhukar Pappireddy 4 months ago
committed by TrustedFirmware Code Review
parent
commit
c970c1c38f
  1. 29
      drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h
  2. 1
      drivers/nxp/clk/s32cc/s32cc_clk.mk
  3. 200
      drivers/nxp/clk/s32cc/s32cc_clk_drv.c
  4. 46
      drivers/nxp/clk/s32cc/s32cc_clk_modules.c
  5. 15
      drivers/nxp/clk/s32cc/s32cc_early_clks.c
  6. 100
      include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h

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

1
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 \

200
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 @@ static int update_stack_depth(unsigned int *depth)
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 @@ static int set_module_rate(const struct s32cc_clk_obj *module,
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_get_parent(unsigned long id)
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)

46
drivers/nxp/clk/s32cc/s32cc_clk_modules.c

@ -23,11 +23,38 @@ static struct s32cc_osc sirc =
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 @@ static struct s32cc_clk_array s32cc_hw_clocks = {
.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);

15
drivers/nxp/clk/s32cc/s32cc_early_clks.c

@ -16,10 +16,25 @@ int s32cc_init_early_clks(void)
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;
}

100
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 @@ struct s32cc_osc {
.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 @@ static inline struct s32cc_clk *s32cc_obj2clk(const struct s32cc_clk_obj *mod)
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 */

Loading…
Cancel
Save