From af3020e2ae86b71a87d936bb5e7181393874d708 Mon Sep 17 00:00:00 2001 From: Ghennadi Procopciuc Date: Wed, 11 Sep 2024 15:09:43 +0300 Subject: [PATCH 1/7] feat(nxp-clk): add partitions objects The S32CC-based SoCs are organized in partitions. These are software-resettable domains in which configuration participates in MC_CGM, MC_ME, and RDC modules. A partition is an island that may contain multiple blocks, each of which corresponds to a peripheral or a core and can, in most cases, be reset individually. This reset structure results in better device availability. If a fault is detected in a software reset domain, that domain can be reset separately without impacting the operation of the rest of the chip. Change-Id: Ie60dbe151309209e377aa71356dbbd6a4f376a8c Signed-off-by: Ghennadi Procopciuc --- .../drivers/nxp/clk/s32cc/s32cc-clk-modules.h | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h b/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h index a6d58cc0a..acad3cd5a 100644 --- a/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h +++ b/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h @@ -22,6 +22,9 @@ enum s32cc_clkm_type { 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 { @@ -208,6 +211,76 @@ struct s32cc_clk_array { #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; @@ -294,4 +367,30 @@ static inline struct s32cc_dfs_div *s32cc_obj2dfsdiv(const struct s32cc_clk_obj 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 */ From 11a7c54072f651512948446e432421ba7ee57469 Mon Sep 17 00:00:00 2001 From: Ghennadi Procopciuc Date: Mon, 16 Sep 2024 16:20:08 +0300 Subject: [PATCH 2/7] feat(nxp-clk): add partition reset utilities MC_RGM is a hardware block involved in resetting peripherals and partitions. Here, the accessories for partition reset are added. Change-Id: If00755fe0e93ba2e4841f95ed5ae3c87db20bebf Signed-off-by: Ghennadi Procopciuc --- drivers/nxp/clk/s32cc/include/s32cc-mc-rgm.h | 2 ++ drivers/nxp/clk/s32cc/mc_rgm.c | 21 +++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/nxp/clk/s32cc/include/s32cc-mc-rgm.h b/drivers/nxp/clk/s32cc/include/s32cc-mc-rgm.h index 5ff55fb6a..d6234daf8 100644 --- a/drivers/nxp/clk/s32cc/include/s32cc-mc-rgm.h +++ b/drivers/nxp/clk/s32cc/include/s32cc-mc-rgm.h @@ -8,5 +8,7 @@ #include void mc_rgm_periph_reset(uintptr_t rgm, uint32_t part, uint32_t value); +void mc_rgm_release_part(uintptr_t rgm, uint32_t part); +void mc_rgm_wait_part_deassert(uintptr_t rgm, uint32_t part); #endif /* MC_RGM_H */ diff --git a/drivers/nxp/clk/s32cc/mc_rgm.c b/drivers/nxp/clk/s32cc/mc_rgm.c index cbf402240..c66b01391 100644 --- a/drivers/nxp/clk/s32cc/mc_rgm.c +++ b/drivers/nxp/clk/s32cc/mc_rgm.c @@ -7,7 +7,10 @@ #include #include -#define MC_RGM_PRST(MC_RGM, PER) ((MC_RGM) + 0x40UL + ((PER) * 0x8UL)) +#define MC_RGM_PRST(RGM, PER) ((RGM) + 0x40UL + ((PER) * 0x8UL)) +#define MC_RGM_PRST_PERIPH_N_RST(PER) BIT_32(PER) +#define MC_RGM_PSTAT(RGM, PER) ((RGM) + 0x140UL + ((PER) * 0x8UL)) +#define MC_RGM_PSTAT_PERIPH(PER) BIT_32(PER) /* ERR051700 * Releasing more than one Software Resettable Domain (SRD) @@ -63,3 +66,19 @@ void mc_rgm_periph_reset(uintptr_t rgm, uint32_t part, uint32_t value) mmio_write_32(MC_RGM_PRST(rgm, part), value); } #endif /* ERRATA_S32_051700 */ + +void mc_rgm_release_part(uintptr_t rgm, uint32_t part) +{ + uint32_t reg; + + reg = mmio_read_32(MC_RGM_PRST(rgm, part)); + reg &= ~MC_RGM_PRST_PERIPH_N_RST(0); + mc_rgm_periph_reset(rgm, part, reg); +} + +void mc_rgm_wait_part_deassert(uintptr_t rgm, uint32_t part) +{ + while ((mmio_read_32(MC_RGM_PSTAT(rgm, part)) & + MC_RGM_PSTAT_PERIPH(0)) != 0U) { + } +} From b8c68ad799523229ed7c0a9d025b22f74ffe9eed Mon Sep 17 00:00:00 2001 From: Ghennadi Procopciuc Date: Mon, 16 Sep 2024 16:22:55 +0300 Subject: [PATCH 3/7] feat(nxp-clk): add MC_ME utilities MC_ME is one of the leading hardware blocks responsible for partitions' transition to and from a reset state. Not being the only one involved in this role, it must cooperate with some other modules (MC_RGM, RDC) to successfully bring a peripheral out of the reset state. As a result, the partition management is isolated into a dedicated file, as parts of it will later contribute to peripheral reset control. Change-Id: I6a9dbf28008b1677bc847bbafa474b489c999d05 Signed-off-by: Ghennadi Procopciuc --- drivers/nxp/clk/s32cc/include/s32cc-mc-me.h | 16 ++ drivers/nxp/clk/s32cc/mc_me.c | 173 ++++++++++++++++++++ drivers/nxp/clk/s32cc/s32cc_clk.mk | 1 + 3 files changed, 190 insertions(+) create mode 100644 drivers/nxp/clk/s32cc/include/s32cc-mc-me.h create mode 100644 drivers/nxp/clk/s32cc/mc_me.c diff --git a/drivers/nxp/clk/s32cc/include/s32cc-mc-me.h b/drivers/nxp/clk/s32cc/include/s32cc-mc-me.h new file mode 100644 index 000000000..8249fc55f --- /dev/null +++ b/drivers/nxp/clk/s32cc/include/s32cc-mc-me.h @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright 2020-2021, 2023-2024 NXP + */ +#ifndef S32CC_MC_ME_H +#define S32CC_MC_ME_H + +#include +#include + +int mc_me_enable_partition(uintptr_t mc_me, uintptr_t mc_rgm, uintptr_t rdc, + uint32_t part); +void mc_me_enable_part_cofb(uintptr_t mc_me, uint32_t partition_n, uint32_t block, + bool check_status); + +#endif /* S32CC_MC_ME_H */ diff --git a/drivers/nxp/clk/s32cc/mc_me.c b/drivers/nxp/clk/s32cc/mc_me.c new file mode 100644 index 000000000..04d04253d --- /dev/null +++ b/drivers/nxp/clk/s32cc/mc_me.c @@ -0,0 +1,173 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#define MC_ME_MAX_PARTITIONS (4U) + +#define MC_ME_CTL_KEY(MC_ME) ((MC_ME) + 0x0UL) +#define MC_ME_CTL_KEY_KEY (0x5AF0U) +#define MC_ME_CTL_KEY_INVERTEDKEY (0xA50FU) + +#define MC_ME_PRTN_N(MC_ME, PART) ((MC_ME) + 0x100UL + ((PART) * 0x200UL)) +#define MC_ME_PRTN_N_PCONF(MC_ME, PART) (MC_ME_PRTN_N(MC_ME, PART)) +#define MC_ME_PRTN_N_PCE BIT_32(0) +#define MC_ME_PRTN_N_OSSE BIT_32(2) +#define MC_ME_PRTN_N_PUPD(MC_ME, PART) (MC_ME_PRTN_N(MC_ME, PART) + 0x4UL) +#define MC_ME_PRTN_N_PCUD BIT_32(0) +#define MC_ME_PRTN_N_OSSUD BIT_32(2) +#define MC_ME_PRTN_N_STAT(MC_ME, PART) (MC_ME_PRTN_N(MC_ME, PART) + 0x8UL) +#define MC_ME_PRTN_N_PCS BIT_32(0) +#define MC_ME_PRTN_N_COFB0_STAT(MC_ME, PART) \ + (MC_ME_PRTN_N(MC_ME, PART) + 0x10UL) +#define MC_ME_PRTN_N_COFB0_CLKEN(MC_ME, PART) \ + (MC_ME_PRTN_N(MC_ME, PART) + 0x30UL) +#define MC_ME_PRTN_N_REQ(PART) BIT_32(PART) + +#define RDC_RD_CTRL(RDC, PART) ((RDC) + ((PART) * 0x4UL)) +#define RDC_CTRL_UNLOCK BIT_32(31) +#define RDC_RD_INTERCONNECT_DISABLE BIT_32(3) + +#define RDC_RD_N_STATUS(RDC, PART) ((RDC) + ((PART) * 0x4UL) + 0x80UL) +#define RDC_RD_INTERCONNECT_DISABLE_STAT \ + BIT_32(4) + +static bool is_interconnect_disabled(uintptr_t rdc, uint32_t part) +{ + return ((mmio_read_32(RDC_RD_N_STATUS(rdc, part)) & + RDC_RD_INTERCONNECT_DISABLE_STAT) != 0U); +} + +static void enable_interconnect(uintptr_t rdc, uint32_t part) +{ + /* Unlock RDC register write */ + mmio_setbits_32(RDC_RD_CTRL(rdc, part), RDC_CTRL_UNLOCK); + + /* Clear corresponding RDC_RD_INTERCONNECT bit */ + mmio_clrbits_32(RDC_RD_CTRL(rdc, part), RDC_RD_INTERCONNECT_DISABLE); + + /* Wait until the interface gets enabled */ + while (is_interconnect_disabled(rdc, part)) { + } + + /* Lock RDC register write */ + mmio_clrbits_32(RDC_RD_CTRL(rdc, part), RDC_CTRL_UNLOCK); +} + +static int mc_me_check_partition_nb_valid(uint32_t part) +{ + if (part >= MC_ME_MAX_PARTITIONS) { + ERROR("Invalid partition %" PRIu32 "\n", part); + return -EINVAL; + } + + return 0; +} + +static void part_pconf_write_pce(uintptr_t mc_me, uint32_t pce_bit, + uint32_t part) +{ + mmio_clrsetbits_32(MC_ME_PRTN_N_PCONF(mc_me, part), MC_ME_PRTN_N_PCE, + pce_bit & MC_ME_PRTN_N_PCE); +} + +static void mc_me_apply_hw_changes(uintptr_t mc_me) +{ + mmio_write_32(MC_ME_CTL_KEY(mc_me), MC_ME_CTL_KEY_KEY); + mmio_write_32(MC_ME_CTL_KEY(mc_me), MC_ME_CTL_KEY_INVERTEDKEY); +} + +static void part_pupd_update_and_wait(uintptr_t mc_me, uint32_t part, + uint32_t mask) +{ + uint32_t pconf, stat; + + mmio_setbits_32(MC_ME_PRTN_N_PUPD(mc_me, part), mask); + + mc_me_apply_hw_changes(mc_me); + + /* wait for the updates to apply */ + pconf = mmio_read_32(MC_ME_PRTN_N_PCONF(mc_me, part)); + do { + stat = mmio_read_32(MC_ME_PRTN_N_STAT(mc_me, part)); + } while ((stat & mask) != (pconf & mask)); +} + +static void part_pconf_write_osse(uintptr_t mc_me, uint32_t osse_bit, + uint32_t part) +{ + mmio_clrsetbits_32(MC_ME_PRTN_N_PCONF(mc_me, part), MC_ME_PRTN_N_OSSE, + (osse_bit & MC_ME_PRTN_N_OSSE)); +} + +int mc_me_enable_partition(uintptr_t mc_me, uintptr_t mc_rgm, uintptr_t rdc, + uint32_t part) +{ + uint32_t part_stat; + int ret; + + /* Partition 0 is already enabled by BootROM */ + if (part == 0U) { + return 0; + } + + ret = mc_me_check_partition_nb_valid(part); + if (ret != 0) { + return ret; + } + + /* Enable a partition only if it's disabled */ + part_stat = mmio_read_32(MC_ME_PRTN_N_STAT(mc_me, part)); + if ((MC_ME_PRTN_N_PCS & part_stat) != 0U) { + return 0; + } + + part_pconf_write_pce(mc_me, MC_ME_PRTN_N_PCE, part); + part_pupd_update_and_wait(mc_me, part, MC_ME_PRTN_N_PCUD); + + enable_interconnect(rdc, part); + + /* Release partition reset */ + mc_rgm_release_part(mc_rgm, part); + + /* Clear OSSE bit */ + part_pconf_write_osse(mc_me, 0, part); + + part_pupd_update_and_wait(mc_me, part, MC_ME_PRTN_N_OSSUD); + + mc_rgm_wait_part_deassert(mc_rgm, part); + + return 0; +} + +void mc_me_enable_part_cofb(uintptr_t mc_me, uint32_t partition_n, uint32_t block, + bool check_status) +{ + uint32_t block_mask = MC_ME_PRTN_N_REQ(block); + uintptr_t cofb_stat_addr; + + mmio_setbits_32(MC_ME_PRTN_N_COFB0_CLKEN(mc_me, partition_n), + block_mask); + + mmio_setbits_32(MC_ME_PRTN_N_PCONF(mc_me, partition_n), + MC_ME_PRTN_N_PCE); + + part_pupd_update_and_wait(mc_me, partition_n, MC_ME_PRTN_N_PCUD); + + cofb_stat_addr = MC_ME_PRTN_N_COFB0_STAT(mc_me, partition_n); + if (check_status) { + while ((mmio_read_32(cofb_stat_addr) & block_mask) == 0U) { + } + } +} diff --git a/drivers/nxp/clk/s32cc/s32cc_clk.mk b/drivers/nxp/clk/s32cc/s32cc_clk.mk index 2a9a37661..602179e3b 100644 --- a/drivers/nxp/clk/s32cc/s32cc_clk.mk +++ b/drivers/nxp/clk/s32cc/s32cc_clk.mk @@ -10,6 +10,7 @@ PLAT_INCLUDES += \ CLK_SOURCES := \ ${PLAT_DRIVERS_PATH}/clk/s32cc/mc_rgm.c \ + ${PLAT_DRIVERS_PATH}/clk/s32cc/mc_me.c \ ${PLAT_DRIVERS_PATH}/clk/s32cc/s32cc_clk_drv.c \ ${PLAT_DRIVERS_PATH}/clk/s32cc/s32cc_clk_modules.c \ ${PLAT_DRIVERS_PATH}/clk/s32cc/s32cc_clk_utils.c \ From 18c2b137f84fed5929ee5f21cbec9260670814a2 Mon Sep 17 00:00:00 2001 From: Ghennadi Procopciuc Date: Mon, 9 Sep 2024 10:24:35 +0300 Subject: [PATCH 4/7] feat(nxp-clk): setup the DDR PLL Add the DDR PLL instance and configure it to operate at its maximum allowed frequency. Change-Id: I96efd68687de78f70759f631d10a0f611c234c8d Signed-off-by: Ghennadi Procopciuc --- .../nxp/clk/s32cc/include/s32cc-clk-regs.h | 1 + drivers/nxp/clk/s32cc/s32cc_clk_drv.c | 6 ++++ drivers/nxp/clk/s32cc/s32cc_early_clks.c | 29 +++++++++++++++++++ include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h | 4 +++ .../drivers/nxp/clk/s32cc/s32cc-clk-modules.h | 1 + 5 files changed, 41 insertions(+) diff --git a/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h b/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h index 84e76f77e..f49f8757d 100644 --- a/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h +++ b/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h @@ -13,6 +13,7 @@ #define ARM_DFS_BASE_ADDR (0x40054000UL) #define CGM0_BASE_ADDR (0x40030000UL) #define CGM1_BASE_ADDR (0x40034000UL) +#define DDRPLL_BASE_ADDR (0x40044000UL) /* FXOSC */ #define FXOSC_CTRL(FXOSC) ((FXOSC) + 0x0UL) diff --git a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c index 14b03d96c..009bd6b2d 100644 --- a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c +++ b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c @@ -26,6 +26,7 @@ struct s32cc_clk_drv { uintptr_t armdfs_base; uintptr_t cgm0_base; uintptr_t cgm1_base; + uintptr_t ddrpll_base; }; static int update_stack_depth(unsigned int *depth) @@ -47,6 +48,7 @@ static struct s32cc_clk_drv *get_drv(void) .armdfs_base = ARM_DFS_BASE_ADDR, .cgm0_base = CGM0_BASE_ADDR, .cgm1_base = CGM1_BASE_ADDR, + .ddrpll_base = DDRPLL_BASE_ADDR, }; return &driver; @@ -86,6 +88,9 @@ static int get_base_addr(enum s32cc_clk_source id, const struct s32cc_clk_drv *d case S32CC_PERIPH_PLL: *base = drv->periphpll_base; break; + case S32CC_DDR_PLL: + *base = drv->ddrpll_base; + break; case S32CC_ARM_DFS: *base = drv->armdfs_base; break; @@ -585,6 +590,7 @@ static int enable_mux(struct s32cc_clk_obj *module, /* PLL mux will be enabled by PLL setup */ case S32CC_ARM_PLL: case S32CC_PERIPH_PLL: + case S32CC_DDR_PLL: break; case S32CC_CGM1: ret = enable_cgm_mux(mux, drv); diff --git a/drivers/nxp/clk/s32cc/s32cc_early_clks.c b/drivers/nxp/clk/s32cc/s32cc_early_clks.c index 3f6d3d7ce..512ee5541 100644 --- a/drivers/nxp/clk/s32cc/s32cc_early_clks.c +++ b/drivers/nxp/clk/s32cc/s32cc_early_clks.c @@ -16,6 +16,8 @@ #define S32CC_XBAR_2X_FREQ (800U * MHZ) #define S32CC_PERIPH_PLL_VCO_FREQ (2U * GHZ) #define S32CC_PERIPH_PLL_PHI3_FREQ UART_CLOCK_HZ +#define S32CC_DDR_PLL_VCO_FREQ (1600U * MHZ) +#define S32CC_DDR_PLL_PHI0_FREQ (800U * MHZ) static int setup_fxosc(void) { @@ -139,6 +141,28 @@ static int enable_uart_clk(void) return ret; } +static int setup_ddr_pll(void) +{ + int ret; + + ret = clk_set_parent(S32CC_CLK_DDR_PLL_MUX, S32CC_CLK_FXOSC); + if (ret != 0) { + return ret; + } + + ret = clk_set_rate(S32CC_CLK_DDR_PLL_VCO, S32CC_DDR_PLL_VCO_FREQ, NULL); + if (ret != 0) { + return ret; + } + + ret = clk_set_rate(S32CC_CLK_DDR_PLL_PHI0, S32CC_DDR_PLL_PHI0_FREQ, NULL); + if (ret != 0) { + return ret; + } + + return ret; +} + int s32cc_init_early_clks(void) { int ret; @@ -175,5 +199,10 @@ int s32cc_init_early_clks(void) return ret; } + ret = setup_ddr_pll(); + if (ret != 0) { + return ret; + } + return ret; } diff --git a/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h b/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h index de633ae20..32287cfe2 100644 --- a/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h +++ b/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h @@ -95,4 +95,8 @@ #define S32CC_CLK_LINFLEX_BAUD S32CC_ARCH_CLK(16) #define S32CC_CLK_LINFLEX S32CC_ARCH_CLK(17) +/* DDR PLL */ +#define S32CC_CLK_DDR_PLL_MUX S32CC_ARCH_CLK(18) +#define S32CC_CLK_DDR_PLL_VCO S32CC_ARCH_CLK(19) + #endif /* S32CC_CLK_IDS_H */ diff --git a/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h b/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h index acad3cd5a..26d2782f3 100644 --- a/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h +++ b/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h @@ -36,6 +36,7 @@ enum s32cc_clk_source { S32CC_PERIPH_PLL, S32CC_CGM0, S32CC_CGM1, + S32CC_DDR_PLL, }; struct s32cc_clk_obj { From 4a2ca718571b3b46cd091cac50c83e9f76c5927b Mon Sep 17 00:00:00 2001 From: Ghennadi Procopciuc Date: Tue, 17 Sep 2024 09:02:24 +0300 Subject: [PATCH 5/7] feat(nxp-clk): add objects needed for DDR clock The DDR clock can be powered by either a PLL or an oscillator. An MC_CGM mux selects between these two clock sources. A reset block, part of partition 0, is also connected to this IP block. Therefore, all the dependencies mentioned above must be configured to have a working clock. Change-Id: Ia841428db9acb95c59ea851b6afeb0b7ff9230a2 Signed-off-by: Ghennadi Procopciuc --- drivers/nxp/clk/s32cc/s32cc_clk_modules.c | 49 ++++++++++++++++++- include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h | 4 ++ .../drivers/nxp/clk/s32cc/s32cc-clk-modules.h | 1 + 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/drivers/nxp/clk/s32cc/s32cc_clk_modules.c b/drivers/nxp/clk/s32cc/s32cc_clk_modules.c index 17ded0e56..71055abc0 100644 --- a/drivers/nxp/clk/s32cc/s32cc_clk_modules.c +++ b/drivers/nxp/clk/s32cc/s32cc_clk_modules.c @@ -10,6 +10,9 @@ #define S32CC_A53_MIN_FREQ (48UL * MHZ) #define S32CC_A53_MAX_FREQ (1000UL * MHZ) +/* Partitions */ +static struct s32cc_part part0 = S32CC_PART(0); + /* Oscillators */ static struct s32cc_osc fxosc = S32CC_OSC_INIT(S32CC_FXOSC); @@ -139,7 +142,40 @@ static struct s32cc_pll_out_div periph_pll_phi3_div = static struct s32cc_clk periph_pll_phi3_clk = S32CC_FREQ_MODULE_CLK(periph_pll_phi3_div, 0, 133333333); -static struct s32cc_clk *s32cc_hw_clk_list[22] = { +/* DDR PLL */ +static struct s32cc_clkmux ddr_pll_mux = + S32CC_CLKMUX_INIT(S32CC_DDR_PLL, 0, 2, + S32CC_CLK_FIRC, + S32CC_CLK_FXOSC, 0, 0, 0); +static struct s32cc_clk ddr_pll_mux_clk = + S32CC_MODULE_CLK(ddr_pll_mux); +static struct s32cc_pll ddrpll = + S32CC_PLL_INIT(ddr_pll_mux_clk, S32CC_DDR_PLL, 1); +static struct s32cc_clk ddr_pll_vco_clk = + S32CC_FREQ_MODULE_CLK(ddrpll, 1300 * MHZ, 1600 * MHZ); + +static struct s32cc_pll_out_div ddr_pll_phi0_div = + S32CC_PLL_OUT_DIV_INIT(ddrpll, 0); +static struct s32cc_clk ddr_pll_phi0_clk = + S32CC_FREQ_MODULE_CLK(ddr_pll_phi0_div, 0, 800 * MHZ); + +/* MC_CGM5 */ +static struct s32cc_clkmux cgm5_mux0 = + S32CC_SHARED_CLKMUX_INIT(S32CC_CGM5, 0, 2, + S32CC_CLK_FIRC, + S32CC_CLK_DDR_PLL_PHI0, + 0, 0, 0); +static struct s32cc_clk cgm5_mux0_clk = S32CC_MODULE_CLK(cgm5_mux0); + +/* DDR clock */ +static struct s32cc_part_block part0_block1 = + S32CC_PART_BLOCK(&part0, s32cc_part_block1); +static struct s32cc_part_block_link ddr_block_link = + S32CC_PART_BLOCK_LINK(cgm5_mux0_clk, &part0_block1); +static struct s32cc_clk ddr_clk = + S32CC_FREQ_MODULE_CLK(ddr_block_link, 0, 800 * MHZ); + +static struct s32cc_clk *s32cc_hw_clk_list[37] = { /* Oscillators */ [S32CC_CLK_ID(S32CC_CLK_FIRC)] = &firc_clk, [S32CC_CLK_ID(S32CC_CLK_SIRC)] = &sirc_clk, @@ -150,6 +186,8 @@ static struct s32cc_clk *s32cc_hw_clk_list[22] = { [S32CC_CLK_ID(S32CC_CLK_ARM_PLL_DFS1)] = &arm_dfs1_clk, /* PERIPH PLL */ [S32CC_CLK_ID(S32CC_CLK_PERIPH_PLL_PHI3)] = &periph_pll_phi3_clk, + /* DDR PLL */ + [S32CC_CLK_ID(S32CC_CLK_DDR_PLL_PHI0)] = &ddr_pll_phi0_clk, }; static struct s32cc_clk_array s32cc_hw_clocks = { @@ -158,7 +196,7 @@ static struct s32cc_clk_array s32cc_hw_clocks = { .n_clks = ARRAY_SIZE(s32cc_hw_clk_list), }; -static struct s32cc_clk *s32cc_arch_clk_list[18] = { +static struct s32cc_clk *s32cc_arch_clk_list[22] = { /* 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, @@ -184,6 +222,13 @@ static struct s32cc_clk *s32cc_arch_clk_list[18] = { /* Linflex */ [S32CC_CLK_ID(S32CC_CLK_LINFLEX)] = &linflex_clk, [S32CC_CLK_ID(S32CC_CLK_LINFLEX_BAUD)] = &linflex_baud_clk, + /* DDR PLL */ + [S32CC_CLK_ID(S32CC_CLK_DDR_PLL_MUX)] = &ddr_pll_mux_clk, + [S32CC_CLK_ID(S32CC_CLK_DDR_PLL_VCO)] = &ddr_pll_vco_clk, + /* MC_CGM5 */ + [S32CC_CLK_ID(S32CC_CLK_MC_CGM5_MUX0)] = &cgm5_mux0_clk, + /* DDR */ + [S32CC_CLK_ID(S32CC_CLK_DDR)] = &ddr_clk, }; static struct s32cc_clk_array s32cc_arch_clocks = { diff --git a/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h b/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h index 32287cfe2..d34dc22fc 100644 --- a/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h +++ b/include/drivers/nxp/clk/s32cc/s32cc-clk-ids.h @@ -99,4 +99,8 @@ #define S32CC_CLK_DDR_PLL_MUX S32CC_ARCH_CLK(18) #define S32CC_CLK_DDR_PLL_VCO S32CC_ARCH_CLK(19) +/* DDR clock */ +#define S32CC_CLK_MC_CGM5_MUX0 S32CC_ARCH_CLK(20) +#define S32CC_CLK_DDR S32CC_ARCH_CLK(21) + #endif /* S32CC_CLK_IDS_H */ diff --git a/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h b/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h index 26d2782f3..4837f795b 100644 --- a/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h +++ b/include/drivers/nxp/clk/s32cc/s32cc-clk-modules.h @@ -37,6 +37,7 @@ enum s32cc_clk_source { S32CC_CGM0, S32CC_CGM1, S32CC_DDR_PLL, + S32CC_CGM5, }; struct s32cc_clk_obj { From 8a4f840b1e13b0187b373e014ea314c3dabb122d Mon Sep 17 00:00:00 2001 From: Ghennadi Procopciuc Date: Tue, 17 Sep 2024 11:22:30 +0300 Subject: [PATCH 6/7] feat(nxp-clk): enable the DDR clock Enable the DDR clock by setting up its reset block, the associated partition and configuring the clock tree above the MC_CGM mux. Change-Id: Idfed24b3e74a189df87f9782886a91b906cd2022 Signed-off-by: Ghennadi Procopciuc --- .../nxp/clk/s32cc/include/s32cc-clk-regs.h | 4 + drivers/nxp/clk/s32cc/s32cc_clk_drv.c | 109 +++++++++++++++++- drivers/nxp/clk/s32cc/s32cc_early_clks.c | 22 ++++ 3 files changed, 130 insertions(+), 5 deletions(-) diff --git a/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h b/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h index f49f8757d..e54d58130 100644 --- a/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h +++ b/drivers/nxp/clk/s32cc/include/s32cc-clk-regs.h @@ -14,6 +14,10 @@ #define CGM0_BASE_ADDR (0x40030000UL) #define CGM1_BASE_ADDR (0x40034000UL) #define DDRPLL_BASE_ADDR (0x40044000UL) +#define MC_ME_BASE_ADDR (0x40088000UL) +#define MC_RGM_BASE_ADDR (0x40078000UL) +#define RDC_BASE_ADDR (0x40080000UL) +#define MC_CGM5_BASE_ADDR (0x40068000UL) /* FXOSC */ #define FXOSC_CTRL(FXOSC) ((FXOSC) + 0x0UL) diff --git a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c index 009bd6b2d..2ff227d6c 100644 --- a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c +++ b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c @@ -4,15 +4,14 @@ * SPDX-License-Identifier: BSD-3-Clause */ #include - -#include - #include #include #include #include #include +#include #include +#include #define MAX_STACK_DEPTH (40U) @@ -26,7 +25,11 @@ struct s32cc_clk_drv { uintptr_t armdfs_base; uintptr_t cgm0_base; uintptr_t cgm1_base; + uintptr_t cgm5_base; uintptr_t ddrpll_base; + uintptr_t mc_me; + uintptr_t mc_rgm; + uintptr_t rdc; }; static int update_stack_depth(unsigned int *depth) @@ -48,7 +51,11 @@ static struct s32cc_clk_drv *get_drv(void) .armdfs_base = ARM_DFS_BASE_ADDR, .cgm0_base = CGM0_BASE_ADDR, .cgm1_base = CGM1_BASE_ADDR, + .cgm5_base = MC_CGM5_BASE_ADDR, .ddrpll_base = DDRPLL_BASE_ADDR, + .mc_me = MC_ME_BASE_ADDR, + .mc_rgm = MC_RGM_BASE_ADDR, + .rdc = RDC_BASE_ADDR, }; return &driver; @@ -100,6 +107,9 @@ static int get_base_addr(enum s32cc_clk_source id, const struct s32cc_clk_drv *d case S32CC_CGM1: *base = drv->cgm1_base; break; + case S32CC_CGM5: + *base = drv->cgm5_base; + break; case S32CC_FIRC: break; case S32CC_SIRC: @@ -598,6 +608,9 @@ static int enable_mux(struct s32cc_clk_obj *module, case S32CC_CGM0: ret = enable_cgm_mux(mux, drv); break; + case S32CC_CGM5: + ret = enable_cgm_mux(mux, drv); + break; default: ERROR("Unknown mux parent type: %d\n", mux->module); ret = -EINVAL; @@ -827,6 +840,86 @@ typedef int (*enable_clk_t)(struct s32cc_clk_obj *module, const struct s32cc_clk_drv *drv, unsigned int depth); +static int enable_part(struct s32cc_clk_obj *module, + const struct s32cc_clk_drv *drv, + unsigned int depth) +{ + const struct s32cc_part *part = s32cc_obj2part(module); + uint32_t part_no = part->partition_id; + + if ((drv->mc_me == 0UL) || (drv->mc_rgm == 0UL) || (drv->rdc == 0UL)) { + return -EINVAL; + } + + return mc_me_enable_partition(drv->mc_me, drv->mc_rgm, drv->rdc, part_no); +} + +static int enable_part_block(struct s32cc_clk_obj *module, + const struct s32cc_clk_drv *drv, + unsigned int depth) +{ + const struct s32cc_part_block *block = s32cc_obj2partblock(module); + const struct s32cc_part *part = block->part; + uint32_t part_no = part->partition_id; + unsigned int ldepth = depth; + uint32_t cofb; + int ret; + + ret = update_stack_depth(&ldepth); + if (ret != 0) { + return ret; + } + + if ((block->block >= s32cc_part_block0) && + (block->block <= s32cc_part_block15)) { + cofb = (uint32_t)block->block - (uint32_t)s32cc_part_block0; + mc_me_enable_part_cofb(drv->mc_me, part_no, cofb, block->status); + } else { + ERROR("Unknown partition block type: %d\n", block->block); + return -EINVAL; + } + + return 0; +} + +static struct s32cc_clk_obj * +get_part_block_parent(const struct s32cc_clk_obj *module) +{ + const struct s32cc_part_block *block = s32cc_obj2partblock(module); + + return &block->part->desc; +} + +static int enable_module_with_refcount(struct s32cc_clk_obj *module, + const struct s32cc_clk_drv *drv, + unsigned int depth); + +static int enable_part_block_link(struct s32cc_clk_obj *module, + const struct s32cc_clk_drv *drv, + unsigned int depth) +{ + const struct s32cc_part_block_link *link = s32cc_obj2partblocklink(module); + struct s32cc_part_block *block = link->block; + unsigned int ldepth = depth; + int ret; + + ret = update_stack_depth(&ldepth); + if (ret != 0) { + return ret; + } + + /* Move the enablement algorithm to partition tree */ + return enable_module_with_refcount(&block->desc, drv, ldepth); +} + +static struct s32cc_clk_obj * +get_part_block_link_parent(const struct s32cc_clk_obj *module) +{ + const struct s32cc_part_block_link *link = s32cc_obj2partblocklink(module); + + return link->parent; +} + static int no_enable(struct s32cc_clk_obj *module, const struct s32cc_clk_drv *drv, unsigned int depth) @@ -872,7 +965,7 @@ static int enable_module(struct s32cc_clk_obj *module, unsigned int depth) { struct s32cc_clk_obj *parent = get_module_parent(module); - static const enable_clk_t enable_clbs[8] = { + static const enable_clk_t enable_clbs[12] = { [s32cc_clk_t] = no_enable, [s32cc_osc_t] = enable_osc, [s32cc_pll_t] = enable_pll, @@ -881,6 +974,9 @@ static int enable_module(struct s32cc_clk_obj *module, [s32cc_shared_clkmux_t] = enable_mux, [s32cc_dfs_t] = enable_dfs, [s32cc_dfs_div_t] = enable_dfs_div, + [s32cc_part_t] = enable_part, + [s32cc_part_block_t] = enable_part_block, + [s32cc_part_block_link_t] = enable_part_block_link, }; uint32_t index; int ret = 0; @@ -1244,7 +1340,7 @@ typedef struct s32cc_clk_obj *(*get_parent_clb_t)(const struct s32cc_clk_obj *cl static struct s32cc_clk_obj *get_module_parent(const struct s32cc_clk_obj *module) { - static const get_parent_clb_t parents_clbs[8] = { + static const get_parent_clb_t parents_clbs[12] = { [s32cc_clk_t] = get_clk_parent, [s32cc_osc_t] = get_no_parent, [s32cc_pll_t] = get_pll_parent, @@ -1253,6 +1349,9 @@ static struct s32cc_clk_obj *get_module_parent(const struct s32cc_clk_obj *modul [s32cc_shared_clkmux_t] = get_mux_parent, [s32cc_dfs_t] = get_dfs_parent, [s32cc_dfs_div_t] = get_dfs_div_parent, + [s32cc_part_t] = get_no_parent, + [s32cc_part_block_t] = get_part_block_parent, + [s32cc_part_block_link_t] = get_part_block_link_parent, }; uint32_t index; diff --git a/drivers/nxp/clk/s32cc/s32cc_early_clks.c b/drivers/nxp/clk/s32cc/s32cc_early_clks.c index 512ee5541..02b9df93c 100644 --- a/drivers/nxp/clk/s32cc/s32cc_early_clks.c +++ b/drivers/nxp/clk/s32cc/s32cc_early_clks.c @@ -163,6 +163,23 @@ static int setup_ddr_pll(void) return ret; } +static int enable_ddr_clk(void) +{ + int ret; + + ret = clk_set_parent(S32CC_CLK_MC_CGM5_MUX0, S32CC_CLK_DDR_PLL_PHI0); + if (ret != 0) { + return ret; + } + + ret = clk_enable(S32CC_CLK_DDR); + if (ret != 0) { + return ret; + } + + return ret; +} + int s32cc_init_early_clks(void) { int ret; @@ -204,5 +221,10 @@ int s32cc_init_early_clks(void) return ret; } + ret = enable_ddr_clk(); + if (ret != 0) { + return ret; + } + return ret; } From 8ee0fc31992538823177e764e4522293ea829957 Mon Sep 17 00:00:00 2001 From: Ghennadi Procopciuc Date: Mon, 30 Sep 2024 09:39:15 +0300 Subject: [PATCH 7/7] fix(nxp-clk): function parameter should not be modified The function 'update_stack_depth' modifies the value of the 'depth' parameter passed by reference. Typically, the caller recevies this parameter by value, and it is then passed to 'update_stack_depth' by reference. This violates MISRA 17.8 rule. To address this issue, a new local variable is introduced to store the value of 'depth'. Change-Id: Ia37f4ede9e6558f778bdda17b7b195f1f50d0c30 Signed-off-by: Ghennadi Procopciuc --- drivers/nxp/clk/s32cc/s32cc_clk_drv.c | 32 +++++++++++++++++---------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c index 2ff227d6c..9b5760753 100644 --- a/drivers/nxp/clk/s32cc/s32cc_clk_drv.c +++ b/drivers/nxp/clk/s32cc/s32cc_clk_drv.c @@ -155,9 +155,10 @@ static int enable_osc(struct s32cc_clk_obj *module, unsigned int depth) { const struct s32cc_osc *osc = s32cc_obj2osc(module); + unsigned int ldepth = depth; int ret = 0; - ret = update_stack_depth(&depth); + ret = update_stack_depth(&ldepth); if (ret != 0) { return ret; } @@ -336,11 +337,12 @@ static int enable_pll(struct s32cc_clk_obj *module, const struct s32cc_pll *pll = s32cc_obj2pll(module); const struct s32cc_clkmux *mux; uintptr_t pll_addr = UL(0x0); + unsigned int ldepth = depth; unsigned long sclk_freq; uint32_t sclk_id; int ret; - ret = update_stack_depth(&depth); + ret = update_stack_depth(&ldepth); if (ret != 0) { return ret; } @@ -436,11 +438,12 @@ static int enable_pll_div(struct s32cc_clk_obj *module, { const struct s32cc_pll_out_div *pdiv = s32cc_obj2plldiv(module); uintptr_t pll_addr = 0x0ULL; + unsigned int ldepth = depth; const struct s32cc_pll *pll; uint32_t dc; int ret; - ret = update_stack_depth(&depth); + ret = update_stack_depth(&ldepth); if (ret != 0) { return ret; } @@ -577,10 +580,11 @@ static int enable_mux(struct s32cc_clk_obj *module, unsigned int depth) { const struct s32cc_clkmux *mux = s32cc_obj2clkmux(module); + unsigned int ldepth = depth; const struct s32cc_clk *clk; int ret = 0; - ret = update_stack_depth(&depth); + ret = update_stack_depth(&ldepth); if (ret != 0) { return ret; } @@ -635,9 +639,10 @@ static int enable_dfs(struct s32cc_clk_obj *module, const struct s32cc_clk_drv *drv, unsigned int depth) { + unsigned int ldepth = depth; int ret = 0; - ret = update_stack_depth(&depth); + ret = update_stack_depth(&ldepth); if (ret != 0) { return ret; } @@ -801,13 +806,14 @@ static int enable_dfs_div(struct s32cc_clk_obj *module, unsigned int depth) { const struct s32cc_dfs_div *dfs_div = s32cc_obj2dfsdiv(module); + unsigned int ldepth = depth; const struct s32cc_pll *pll; const struct s32cc_dfs *dfs; uintptr_t dfs_addr = 0UL; uint32_t mfi, mfn; int ret = 0; - ret = update_stack_depth(&depth); + ret = update_stack_depth(&ldepth); if (ret != 0) { return ret; } @@ -931,24 +937,25 @@ 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) { + unsigned int ldepth = depth; int ret = 0; if (mod == NULL) { return 0; } - ret = update_stack_depth(&depth); + ret = update_stack_depth(&ldepth); if (ret != 0) { return ret; } /* Refcount will be updated as part of the recursivity */ if (leaf_node) { - return en_cb(mod, drv, depth); + return en_cb(mod, drv, ldepth); } if (mod->refcount == 0U) { - ret = en_cb(mod, drv, depth); + ret = en_cb(mod, drv, ldepth); } if (ret == 0) { @@ -978,10 +985,11 @@ static int enable_module(struct s32cc_clk_obj *module, [s32cc_part_block_t] = enable_part_block, [s32cc_part_block_link_t] = enable_part_block_link, }; + unsigned int ldepth = depth; uint32_t index; int ret = 0; - ret = update_stack_depth(&depth); + ret = update_stack_depth(&ldepth); if (ret != 0) { return ret; } @@ -1006,13 +1014,13 @@ static int enable_module(struct s32cc_clk_obj *module, parent = get_module_parent(module); ret = exec_cb_with_refcount(enable_module, parent, drv, - false, depth); + false, ldepth); if (ret != 0) { return ret; } ret = exec_cb_with_refcount(enable_clbs[index], module, drv, - true, depth); + true, ldepth); if (ret != 0) { return ret; }