| /* SPDX-License-Identifier: BSD-3-Clause */ |
| /* |
| * Copyright 2020-2024 NXP |
| */ |
| #ifndef S32CC_CLK_MODULES_H |
| #define S32CC_CLK_MODULES_H |
| |
| #include <inttypes.h> |
| #include <stdbool.h> |
| #include <stddef.h> |
| |
| #define MHZ UL(1000000) |
| #define GHZ (UL(1000) * MHZ) |
| |
| enum s32cc_clkm_type { |
| s32cc_osc_t, |
| s32cc_clk_t, |
| s32cc_pll_t, |
| s32cc_pll_out_div_t, |
| s32cc_dfs_t, |
| s32cc_dfs_div_t, |
| s32cc_clkmux_t, |
| s32cc_shared_clkmux_t, |
| s32cc_fixed_div_t, |
| s32cc_part_t, |
| s32cc_part_block_t, |
| s32cc_part_block_link_t, |
| }; |
| |
| enum s32cc_clk_source { |
| S32CC_FIRC, |
| S32CC_FXOSC, |
| S32CC_SIRC, |
| S32CC_ARM_PLL, |
| S32CC_ARM_DFS, |
| S32CC_PERIPH_PLL, |
| S32CC_CGM0, |
| S32CC_CGM1, |
| S32CC_DDR_PLL, |
| S32CC_CGM5, |
| }; |
| |
| struct s32cc_clk_obj { |
| enum s32cc_clkm_type type; |
| uint32_t refcount; |
| }; |
| |
| struct s32cc_osc { |
| struct s32cc_clk_obj desc; |
| enum s32cc_clk_source source; |
| unsigned long freq; |
| void *base; |
| }; |
| |
| #define S32CC_OSC_INIT(SOURCE) \ |
| { \ |
| .desc = { \ |
| .type = s32cc_osc_t, \ |
| }, \ |
| .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), \ |
| } |
| |
| #define S32CC_PLL_OUT_DIV_INIT(PARENT, INDEX) \ |
| { \ |
| .desc = { \ |
| .type = s32cc_pll_out_div_t, \ |
| }, \ |
| .parent = &(PARENT).desc, \ |
| .index = (INDEX), \ |
| } |
| |
| struct s32cc_dfs { |
| struct s32cc_clk_obj desc; |
| struct s32cc_clk_obj *parent; |
| enum s32cc_clk_source instance; |
| uintptr_t base; |
| }; |
| |
| #define S32CC_DFS_INIT(PARENT, INSTANCE) \ |
| { \ |
| .desc = { \ |
| .type = s32cc_dfs_t, \ |
| }, \ |
| .parent = &(PARENT).desc, \ |
| .instance = (INSTANCE), \ |
| } |
| |
| struct s32cc_dfs_div { |
| struct s32cc_clk_obj desc; |
| struct s32cc_clk_obj *parent; |
| uint32_t index; |
| unsigned long freq; |
| }; |
| |
| #define S32CC_DFS_DIV_INIT(PARENT, INDEX) \ |
| { \ |
| .desc = { \ |
| .type = s32cc_dfs_div_t, \ |
| }, \ |
| .parent = &(PARENT).desc, \ |
| .index = (INDEX), \ |
| } |
| |
| struct s32cc_fixed_div { |
| struct s32cc_clk_obj desc; |
| struct s32cc_clk_obj *parent; |
| uint32_t rate_div; |
| }; |
| |
| #define S32CC_FIXED_DIV_INIT(PARENT, RATE_DIV) \ |
| { \ |
| .desc = { \ |
| .type = s32cc_fixed_div_t, \ |
| }, \ |
| .parent = &(PARENT).desc, \ |
| .rate_div = (RATE_DIV), \ |
| } |
| |
| struct s32cc_clk { |
| struct s32cc_clk_obj desc; |
| struct s32cc_clk_obj *module; |
| struct s32cc_clk *pclock; |
| unsigned long min_freq; |
| unsigned long max_freq; |
| }; |
| |
| struct s32cc_clk_array { |
| unsigned long type_mask; |
| struct s32cc_clk **clks; |
| size_t n_clks; |
| }; |
| |
| #define S32CC_FREQ_CLK(PARENT_MODULE, PARENT, MIN_F, MAX_F) \ |
| { \ |
| .desc = { \ |
| .type = s32cc_clk_t, \ |
| }, \ |
| .pclock = (PARENT), \ |
| .module = (PARENT_MODULE), \ |
| .min_freq = (MIN_F), \ |
| .max_freq = (MAX_F), \ |
| } |
| |
| #define S32CC_FREQ_MODULE_CLK(PARENT_MODULE, MIN_F, MAX_F) \ |
| S32CC_FREQ_CLK(&(PARENT_MODULE).desc, NULL, MIN_F, MAX_F) |
| |
| #define S32CC_MODULE_CLK(PARENT_MODULE) \ |
| S32CC_FREQ_MODULE_CLK(PARENT_MODULE, 0, 0) |
| |
| #define S32CC_CHILD_CLK(PARENT, MIN_F, MAX_F) \ |
| S32CC_FREQ_CLK(NULL, &(PARENT), MIN_F, MAX_F) |
| |
| struct s32cc_part { |
| struct s32cc_clk_obj desc; |
| uint32_t partition_id; |
| }; |
| |
| #define S32CC_PART(PART_NUM) \ |
| { \ |
| .desc = { \ |
| .type = s32cc_part_t, \ |
| }, \ |
| .partition_id = (PART_NUM), \ |
| } |
| |
| enum s32cc_part_block_type { |
| s32cc_part_block0, |
| s32cc_part_block1, |
| s32cc_part_block2, |
| s32cc_part_block3, |
| s32cc_part_block4, |
| s32cc_part_block5, |
| s32cc_part_block6, |
| s32cc_part_block7, |
| s32cc_part_block8, |
| s32cc_part_block9, |
| s32cc_part_block10, |
| s32cc_part_block11, |
| s32cc_part_block12, |
| s32cc_part_block13, |
| s32cc_part_block14, |
| s32cc_part_block15, |
| }; |
| |
| struct s32cc_part_block { |
| struct s32cc_clk_obj desc; |
| struct s32cc_part *part; |
| enum s32cc_part_block_type block; |
| bool status; |
| }; |
| |
| #define S32CC_PART_BLOCK_STATUS(PART_META, BLOCK_TYPE, STATUS) \ |
| { \ |
| .desc = { \ |
| .type = s32cc_part_block_t, \ |
| }, \ |
| .part = (PART_META), \ |
| .block = (BLOCK_TYPE), \ |
| .status = (STATUS), \ |
| } |
| |
| #define S32CC_PART_BLOCK(PARENT, BLOCK_TYPE) \ |
| S32CC_PART_BLOCK_STATUS(PARENT, BLOCK_TYPE, true) |
| |
| #define S32CC_PART_BLOCK_NO_STATUS(PARENT, BLOCK_TYPE) \ |
| S32CC_PART_BLOCK_STATUS(PARENT, BLOCK_TYPE, false) |
| |
| struct s32cc_part_block_link { |
| struct s32cc_clk_obj desc; |
| struct s32cc_clk_obj *parent; |
| struct s32cc_part_block *block; |
| }; |
| |
| #define S32CC_PART_BLOCK_LINK(PARENT, BLOCK) \ |
| { \ |
| .desc = { \ |
| .type = s32cc_part_block_link_t, \ |
| }, \ |
| .parent = &(PARENT).desc, \ |
| .block = (BLOCK), \ |
| } |
| |
| static inline struct s32cc_osc *s32cc_obj2osc(const struct s32cc_clk_obj *mod) |
| { |
| uintptr_t osc_addr; |
| |
| osc_addr = ((uintptr_t)mod) - offsetof(struct s32cc_osc, desc); |
| return (struct s32cc_osc *)osc_addr; |
| } |
| |
| static inline struct s32cc_clk *s32cc_obj2clk(const struct s32cc_clk_obj *mod) |
| { |
| uintptr_t clk_addr; |
| |
| clk_addr = ((uintptr_t)mod) - offsetof(struct s32cc_clk, desc); |
| 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); |
| } |
| |
| static inline struct s32cc_pll *s32cc_obj2pll(const struct s32cc_clk_obj *mod) |
| { |
| uintptr_t pll_addr; |
| |
| pll_addr = ((uintptr_t)mod) - offsetof(struct s32cc_pll, desc); |
| return (struct s32cc_pll *)pll_addr; |
| } |
| |
| static inline struct s32cc_pll_out_div *s32cc_obj2plldiv(const struct s32cc_clk_obj *mod) |
| { |
| uintptr_t plldiv_addr; |
| |
| plldiv_addr = ((uintptr_t)mod) - offsetof(struct s32cc_pll_out_div, desc); |
| return (struct s32cc_pll_out_div *)plldiv_addr; |
| } |
| |
| static inline struct s32cc_fixed_div *s32cc_obj2fixeddiv(const struct s32cc_clk_obj *mod) |
| { |
| uintptr_t fdiv_addr; |
| |
| fdiv_addr = ((uintptr_t)mod) - offsetof(struct s32cc_fixed_div, desc); |
| return (struct s32cc_fixed_div *)fdiv_addr; |
| } |
| |
| static inline struct s32cc_dfs *s32cc_obj2dfs(const struct s32cc_clk_obj *mod) |
| { |
| uintptr_t dfs_addr; |
| |
| dfs_addr = ((uintptr_t)mod) - offsetof(struct s32cc_dfs, desc); |
| return (struct s32cc_dfs *)dfs_addr; |
| } |
| |
| static inline struct s32cc_dfs_div *s32cc_obj2dfsdiv(const struct s32cc_clk_obj *mod) |
| { |
| uintptr_t dfs_div_addr; |
| |
| dfs_div_addr = ((uintptr_t)mod) - offsetof(struct s32cc_dfs_div, desc); |
| return (struct s32cc_dfs_div *)dfs_div_addr; |
| } |
| |
| static inline struct s32cc_part *s32cc_obj2part(const struct s32cc_clk_obj *mod) |
| { |
| uintptr_t part_addr; |
| |
| part_addr = ((uintptr_t)mod) - offsetof(struct s32cc_part, desc); |
| return (struct s32cc_part *)part_addr; |
| } |
| |
| static inline struct s32cc_part_block * |
| s32cc_obj2partblock(const struct s32cc_clk_obj *mod) |
| { |
| uintptr_t part_blk_addr; |
| |
| part_blk_addr = ((uintptr_t)mod) - offsetof(struct s32cc_part_block, desc); |
| return (struct s32cc_part_block *)part_blk_addr; |
| } |
| |
| static inline struct s32cc_part_block_link * |
| s32cc_obj2partblocklink(const struct s32cc_clk_obj *mod) |
| { |
| uintptr_t blk_link; |
| |
| blk_link = ((uintptr_t)mod) - offsetof(struct s32cc_part_block_link, desc); |
| return (struct s32cc_part_block_link *)blk_link; |
| } |
| |
| #endif /* S32CC_CLK_MODULES_H */ |