From 5c7ab5c2bfd488d8cfa55a8ca31e7c6b777f9968 Mon Sep 17 00:00:00 2001 From: Mulin Chao Date: Sun, 14 May 2023 23:06:26 -0700 Subject: [PATCH] driver: clock_control: npcx: add support for npcx4 series This CL introduces new clock architectures in npcx4 series and wraps clock configurations of different series by device tree files. For example, the PWDWN_CTLx reg initialization relies on `pwdwn-ctl-val` prop of pcc DT node now. Signed-off-by: Mulin Chao --- drivers/clock_control/clock_control_npcx.c | 64 +++++++++---------- dts/arm/nuvoton/npcx/npcx4.dtsi | 8 +++ dts/arm/nuvoton/npcx/npcx7.dtsi | 7 ++ dts/arm/nuvoton/npcx/npcx9.dtsi | 8 +++ dts/bindings/clock/nuvoton,npcx-pcc.yaml | 14 ++-- include/zephyr/dt-bindings/clock/npcx_clock.h | 2 + soc/arm/nuvoton_npcx/common/soc_clock.h | 64 ++++++++++++++----- 7 files changed, 114 insertions(+), 53 deletions(-) diff --git a/drivers/clock_control/clock_control_npcx.c b/drivers/clock_control/clock_control_npcx.c index 82199d6111d..dcc4a925c99 100644 --- a/drivers/clock_control/clock_control_npcx.c +++ b/drivers/clock_control/clock_control_npcx.c @@ -28,6 +28,8 @@ struct npcx_pcc_config { #define HAL_PMC_INST(dev) \ ((struct pmc_reg *)((const struct npcx_pcc_config *)(dev)->config)->base_pmc) +static uint8_t pddwn_ctl_val[] = {NPCX_PWDWN_CTL_INIT}; + /* Clock controller local functions */ static inline int npcx_clock_control_on(const struct device *dev, clock_control_subsys_t sub_system) @@ -89,6 +91,11 @@ static int npcx_clock_control_get_subsys_rate(const struct device *dev, case NPCX_CLOCK_BUS_FIU: *rate = CORE_CLK/(FIUDIV_VAL + 1); break; +#if defined(FIU1DIV_VAL) + case NPCX_CLOCK_BUS_FIU1: + *rate = CORE_CLK/(FIU1DIV_VAL + 1); + break; +#endif case NPCX_CLOCK_BUS_CORE: *rate = CORE_CLK; break; @@ -144,30 +151,36 @@ static struct clock_control_driver_api npcx_clock_control_api = { }; /* valid clock frequency check */ -BUILD_ASSERT(CORE_CLK <= MHZ(100) && CORE_CLK >= MHZ(4) && +BUILD_ASSERT(OFMCLK <= MAX_OFMCLK, "Exceed maximum OFMCLK setting"); +BUILD_ASSERT(CORE_CLK <= MAX_OFMCLK && CORE_CLK >= MHZ(4) && OFMCLK % CORE_CLK == 0 && OFMCLK / CORE_CLK <= 10, "Invalid CORE_CLK setting"); -BUILD_ASSERT(CORE_CLK / (FIUDIV_VAL + 1) <= MHZ(50) && +BUILD_ASSERT(CORE_CLK / (FIUDIV_VAL + 1) <= (MAX_OFMCLK / 2) && CORE_CLK / (FIUDIV_VAL + 1) >= MHZ(4), "Invalid FIUCLK setting"); -BUILD_ASSERT(CORE_CLK / (AHB6DIV_VAL + 1) <= MHZ(50) && +#if defined(FIU1DIV_VAL) +BUILD_ASSERT(CORE_CLK / (FIU1DIV_VAL + 1) <= (MAX_OFMCLK / 2) && + CORE_CLK / (FIU1DIV_VAL + 1) >= MHZ(4), + "Invalid FIU1CLK setting"); +#endif +BUILD_ASSERT(CORE_CLK / (AHB6DIV_VAL + 1) <= (MAX_OFMCLK / 2) && CORE_CLK / (AHB6DIV_VAL + 1) >= MHZ(4), "Invalid AHB6_CLK setting"); -BUILD_ASSERT(APBSRC_CLK / (APB1DIV_VAL + 1) <= MHZ(50) && +BUILD_ASSERT(APBSRC_CLK / (APB1DIV_VAL + 1) <= (MAX_OFMCLK / 2) && APBSRC_CLK / (APB1DIV_VAL + 1) >= MHZ(4) && (APB1DIV_VAL + 1) % (FPRED_VAL + 1) == 0, "Invalid APB1_CLK setting"); -BUILD_ASSERT(APBSRC_CLK / (APB2DIV_VAL + 1) <= MHZ(50) && +BUILD_ASSERT(APBSRC_CLK / (APB2DIV_VAL + 1) <= (MAX_OFMCLK / 2) && APBSRC_CLK / (APB2DIV_VAL + 1) >= MHZ(8) && (APB2DIV_VAL + 1) % (FPRED_VAL + 1) == 0, "Invalid APB2_CLK setting"); -BUILD_ASSERT(APBSRC_CLK / (APB3DIV_VAL + 1) <= MHZ(50) && +BUILD_ASSERT(APBSRC_CLK / (APB3DIV_VAL + 1) <= (MAX_OFMCLK / 2) && APBSRC_CLK / (APB3DIV_VAL + 1) >= KHZ(12500) && (APB3DIV_VAL + 1) % (FPRED_VAL + 1) == 0, "Invalid APB3_CLK setting"); #if defined(APB4DIV_VAL) -BUILD_ASSERT(APBSRC_CLK / (APB4DIV_VAL + 1) <= MHZ(100) && +BUILD_ASSERT(APBSRC_CLK / (APB4DIV_VAL + 1) <= MAX_OFMCLK && APBSRC_CLK / (APB4DIV_VAL + 1) >= MHZ(8) && (APB4DIV_VAL + 1) % (FPRED_VAL + 1) == 0, "Invalid APB4_CLK setting"); @@ -205,36 +218,23 @@ static int npcx_clock_control_init(const struct device *dev) } /* Set all clock prescalers of core and peripherals. */ - inst_cdcg->HFCGP = ((FPRED_VAL << 4) | AHB6DIV_VAL); - inst_cdcg->HFCBCD = (FIUDIV_VAL << 4); - inst_cdcg->HFCBCD1 = (APB1DIV_VAL | (APB2DIV_VAL << 4)); -#if defined(APB4DIV_VAL) - inst_cdcg->HFCBCD2 = (APB3DIV_VAL | (APB4DIV_VAL << 4)); -#else - inst_cdcg->HFCBCD2 = APB3DIV_VAL; -#endif + inst_cdcg->HFCGP = VAL_HFCGP; + inst_cdcg->HFCBCD = VAL_HFCBCD; + inst_cdcg->HFCBCD1 = VAL_HFCBCD1; + inst_cdcg->HFCBCD2 = VAL_HFCBCD2; /* * Power-down (turn off clock) the modules initially for better * power consumption. */ - NPCX_PWDWN_CTL(pmc_base, NPCX_PWDWN_CTL1) = 0xFB; /* No SDP_PD/FIU_PD */ - NPCX_PWDWN_CTL(pmc_base, NPCX_PWDWN_CTL2) = 0xFF; - NPCX_PWDWN_CTL(pmc_base, NPCX_PWDWN_CTL3) = 0x1F; /* No GDMA_PD */ - NPCX_PWDWN_CTL(pmc_base, NPCX_PWDWN_CTL4) = 0xFF; - NPCX_PWDWN_CTL(pmc_base, NPCX_PWDWN_CTL5) = 0xFA; -#if CONFIG_ESPI - /* Don't gate the clock of the eSPI module if eSPI interface is required */ - NPCX_PWDWN_CTL(pmc_base, NPCX_PWDWN_CTL6) = 0x7F; -#else - NPCX_PWDWN_CTL(pmc_base, NPCX_PWDWN_CTL6) = 0xFF; -#endif -#if defined(CONFIG_SOC_SERIES_NPCX7) - NPCX_PWDWN_CTL(pmc_base, NPCX_PWDWN_CTL7) = 0xE7; -#elif defined(CONFIG_SOC_SERIES_NPCX9) - NPCX_PWDWN_CTL(pmc_base, NPCX_PWDWN_CTL7) = 0xFF; - NPCX_PWDWN_CTL(pmc_base, NPCX_PWDWN_CTL8) = 0x31; -#endif + for (int i = 0; i < ARRAY_SIZE(pddwn_ctl_val); i++) { + NPCX_PWDWN_CTL(pmc_base, i) = pddwn_ctl_val[i]; + } + + /* Turn off the clock of the eSPI module only if eSPI isn't required */ + if (!IS_ENABLED(CONFIG_ESPI)) { + NPCX_PWDWN_CTL(pmc_base, NPCX_PWDWN_CTL6) |= BIT(7); + } return 0; } diff --git a/dts/arm/nuvoton/npcx/npcx4.dtsi b/dts/arm/nuvoton/npcx/npcx4.dtsi index 9087681f28d..cbad55d0df3 100644 --- a/dts/arm/nuvoton/npcx/npcx4.dtsi +++ b/dts/arm/nuvoton/npcx/npcx4.dtsi @@ -115,6 +115,14 @@ apb3-prescaler = <8>; /* APB3_CLK runs at 15MHz */ apb4-prescaler = <8>; /* APB4_CLK runs at 15MHz */ ram-pd-depth = <8>; /* Valid bit-depth of RAM_PDn reg */ + pwdwn-ctl-val = <0xfb + 0xff + 0x1f /* No GDMA1_PD/GDMA2_PD */ + 0xff + 0xfa + 0x7f /* No ESPI_PD */ + 0xff + 0xcf>; /* No FIU_PD */ }; /* Wake-up input source mapping for GPIOs in npcx4 series */ diff --git a/dts/arm/nuvoton/npcx/npcx7.dtsi b/dts/arm/nuvoton/npcx/npcx7.dtsi index ee984d97c7e..7181592c84c 100644 --- a/dts/arm/nuvoton/npcx/npcx7.dtsi +++ b/dts/arm/nuvoton/npcx/npcx7.dtsi @@ -94,6 +94,13 @@ apb2-prescaler = <6>; /* APB2_CLK runs at 15MHz */ apb3-prescaler = <6>; /* APB3_CLK runs at 15MHz */ ram-pd-depth = <12>; /* Valid bit-depth of RAM_PDn reg */ + pwdwn-ctl-val = <0xfb /* No FIU_PD */ + 0xff + 0x1f /* No GDMA_PD */ + 0xff + 0xfa + 0x7f /* No ESPI_PD */ + 0xe7>; }; /* Wake-up input source mapping for GPIOs in npcx7 series */ diff --git a/dts/arm/nuvoton/npcx/npcx9.dtsi b/dts/arm/nuvoton/npcx/npcx9.dtsi index 7c2c47b2e07..14b74e6c262 100644 --- a/dts/arm/nuvoton/npcx/npcx9.dtsi +++ b/dts/arm/nuvoton/npcx/npcx9.dtsi @@ -114,6 +114,14 @@ apb3-prescaler = <6>; /* APB3_CLK runs at 15MHz */ apb4-prescaler = <6>; /* APB4_CLK runs at 15MHz */ ram-pd-depth = <15>; /* Valid bit-depth of RAM_PDn reg */ + pwdwn-ctl-val = <0xfb /* No FIU_PD */ + 0xff + 0x1f /* No GDMA_PD */ + 0xff + 0xfa + 0x7f /* No ESPI_PD */ + 0xff + 0x31>; }; /* Wake-up input source mapping for GPIOs in npcx9 series */ diff --git a/dts/bindings/clock/nuvoton,npcx-pcc.yaml b/dts/bindings/clock/nuvoton,npcx-pcc.yaml index 258e5c67125..00fbf0d87e7 100644 --- a/dts/bindings/clock/nuvoton,npcx-pcc.yaml +++ b/dts/bindings/clock/nuvoton,npcx-pcc.yaml @@ -32,6 +32,7 @@ properties: description: | Default frequency in Hz for HFCG output clock (OFMCLK). Currently, only the following values are allowed: + 120000000, 120 MHz 100000000, 100 MHz 96000000, 96 MHz 90000000, 90 MHz @@ -39,9 +40,8 @@ properties: 66000000, 66 MHz 50000000, 50 MHz 48000000, 48 MHz - 40000000, 40 MHz (default value after reset) - 33000000, 33 MHz enum: + - 120000000 - 100000000 - 96000000 - 90000000 @@ -49,8 +49,6 @@ properties: - 66000000 - 50000000 - 48000000 - - 40000000 - - 33000000 core-prescaler: type: int @@ -208,6 +206,7 @@ properties: ram-pd-depth: type: int enum: + - 8 - 12 - 15 description: | @@ -216,6 +215,13 @@ properties: itself to 1 for better power consumption and this valid bit-depth varies in different NPCX series. + pwdwn-ctl-val: + type: array + required: true + description: | + Power-down (turn off clock) the modules during system initialization for + better power consumption. + clock-cells: - bus - ctl diff --git a/include/zephyr/dt-bindings/clock/npcx_clock.h b/include/zephyr/dt-bindings/clock/npcx_clock.h index adca438f2de..713a05c5726 100644 --- a/include/zephyr/dt-bindings/clock/npcx_clock.h +++ b/include/zephyr/dt-bindings/clock/npcx_clock.h @@ -18,6 +18,8 @@ #define NPCX_CLOCK_BUS_APB4 8 #define NPCX_CLOCK_BUS_AHB6 9 #define NPCX_CLOCK_BUS_FMCLK 10 +#define NPCX_CLOCK_BUS_FIU0 NPCX_CLOCK_BUS_FIU +#define NPCX_CLOCK_BUS_FIU1 11 /* clock enable/disable references */ #define NPCX_PWDWN_CTL1 0 diff --git a/soc/arm/nuvoton_npcx/common/soc_clock.h b/soc/arm/nuvoton_npcx/common/soc_clock.h index afefba88e4b..cda024dc0df 100644 --- a/soc/arm/nuvoton_npcx/common/soc_clock.h +++ b/soc/arm/nuvoton_npcx/common/soc_clock.h @@ -51,15 +51,28 @@ struct npcx_clk_cfg { #endif /* !CONFIG_SOC_SERIES_NPCX7 */ #endif +/* Construct a uint8_t array from 'pwdwn-ctl-val' prop for PWDWN_CTL initialization. */ +#define NPCX_PWDWN_CTL_ITEMS_INIT(node, prop, idx) DT_PROP_BY_IDX(node, prop, idx), +#define NPCX_PWDWN_CTL_INIT DT_FOREACH_PROP_ELEM(DT_NODELABEL(pcc), \ + pwdwn_ctl_val, NPCX_PWDWN_CTL_ITEMS_INIT) + /* * NPCX7 and later series clock tree macros: * (Please refer Figure 58. for more information.) * - * Suggestion: - * - OFMCLK > 50MHz, XF_RANGE should be 1, else 0. - * - CORE_CLK > 50MHz, AHB6DIV should be 1, else 0. - * - CORE_CLK > 50MHz, FIUDIV should be 1, else 0. + * Maximum OFMCLK in npcx7/9 series is 100MHz, + * Maximum OFMCLK in npcx4 series is 120MHz, + * + * Suggestion for npcx series: + * - OFMCLK > MAX_OFMCLK/2, XF_RANGE should be 1, else 0. + * - CORE_CLK > MAX_OFMCLK/2, AHB6DIV should be 1, else 0. + * - CORE_CLK > MAX_OFMCLK/2, FIUDIV should be 1, else 0. */ +#if defined(CONFIG_SOC_SERIES_NPCX4) +#define MAX_OFMCLK 120000000 +#else +#define MAX_OFMCLK 100000000 +#endif /* CONFIG_SOC_SERIES_NPCX4 */ /* Core domain clock */ #define CORE_CLK (OFMCLK / DT_PROP(DT_NODELABEL(pcc), core_prescaler)) @@ -67,8 +80,8 @@ struct npcx_clk_cfg { #define LFCLK 32768 /* FMUL clock */ -#if (OFMCLK > 50000000) -#define FMCLK (OFMCLK / 2) /* FMUL clock = OFMCLK/2 if OFMCLK > 50MHz */ +#if (OFMCLK > (MAX_OFMCLK / 2)) +#define FMCLK (OFMCLK / 2) /* FMUL clock = OFMCLK/2 */ #else #define FMCLK OFMCLK /* FMUL clock = OFMCLK */ #endif @@ -77,18 +90,27 @@ struct npcx_clk_cfg { #define APBSRC_CLK OFMCLK /* AHB6 clock */ -#if (CORE_CLK > 50000000) -#define AHB6DIV_VAL 1 /* AHB6_CLK = CORE_CLK/2 if CORE_CLK > 50MHz */ +#if (CORE_CLK > (MAX_OFMCLK / 2)) +#define AHB6DIV_VAL 1 /* AHB6_CLK = CORE_CLK/2 */ #else #define AHB6DIV_VAL 0 /* AHB6_CLK = CORE_CLK */ #endif + /* FIU clock divider */ -#if (CORE_CLK > 50000000) +#if (CORE_CLK > (MAX_OFMCLK / 2)) #define FIUDIV_VAL 1 /* FIU_CLK = CORE_CLK/2 */ #else #define FIUDIV_VAL 0 /* FIU_CLK = CORE_CLK */ #endif +#if defined(CONFIG_SOC_SERIES_NPCX4) +#if (CORE_CLK > (MAX_OFMCLK / 2)) +#define FIU1DIV_VAL 1 /* FIU1_CLK = CORE_CLK/2 */ +#else +#define FIU1DIV_VAL 0 /* FIU1_CLK = CORE_CLK */ +#endif +#endif /* CONFIG_SOC_SERIES_NPCX4 */ + /* Get APB clock freq */ #define NPCX_APB_CLOCK(no) (APBSRC_CLK / (APB##no##DIV_VAL + 1)) @@ -96,8 +118,8 @@ struct npcx_clk_cfg { * Frequency multiplier M/N value definitions according to the requested * OFMCLK (Unit:Hz). */ -#if (OFMCLK > 50000000) -#define HFCGN_VAL 0x82 /* Set XF_RANGE as 1 if OFMCLK > 50MHz */ +#if (OFMCLK > (MAX_OFMCLK / 2)) +#define HFCGN_VAL 0x82 /* Set XF_RANGE as 1 */ #else #define HFCGN_VAL 0x02 #endif @@ -125,16 +147,24 @@ struct npcx_clk_cfg { #elif (OFMCLK == 48000000) #define HFCGMH_VAL 0x0B #define HFCGML_VAL 0x72 -#elif (OFMCLK == 40000000) -#define HFCGMH_VAL 0x09 -#define HFCGML_VAL 0x89 -#elif (OFMCLK == 33000000) -#define HFCGMH_VAL 0x07 -#define HFCGML_VAL 0xDE #else #error "Unsupported OFMCLK Frequency" #endif +/* Clock prescaler configurations in different series */ +#define VAL_HFCGP ((FPRED_VAL << 4) | AHB6DIV_VAL) +#if defined(FIU1DIV_VAL) +#define VAL_HFCBCD ((FIU1DIV_VAL << 4) | (FIUDIV_VAL << 2)) +#else +#define VAL_HFCBCD (FIUDIV_VAL << 4) +#endif /* FIU1DIV_VAL */ +#define VAL_HFCBCD1 (APB1DIV_VAL | (APB2DIV_VAL << 4)) +#if defined(APB4DIV_VAL) +#define VAL_HFCBCD2 (APB3DIV_VAL | (APB4DIV_VAL << 4)) +#else +#define VAL_HFCBCD2 APB3DIV_VAL +#endif /* APB4DIV_VAL */ + /** * @brief Function to notify clock driver that backup the counter value of * low-frequency timer before ec entered deep idle state.