Skip to content

clock_control: stm32: mp13: add plls / mco & clock source selection #89773

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion boards/st/stm32mp135f_dk/stm32mp135f_dk.dts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
div-m = <2>;
mul-n = <83>;
div-p = <1>;
frac-v = <2730>;
fracn = <2730>;
status = "okay";
};

Expand Down
82 changes: 79 additions & 3 deletions drivers/clock_control/clock_stm32_ll_mp13.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,29 @@
#include <zephyr/drivers/clock_control/stm32_clock_control.h>
#include <zephyr/sys/util.h>

/** @brief Verifies clock is part of active clock configuration */
int enabled_clock(uint32_t src_clk)
{
if ((src_clk == STM32_SRC_HSE && IS_ENABLED(STM32_HSE_ENABLED)) ||
(src_clk == STM32_SRC_HSI && IS_ENABLED(STM32_HSI_ENABLED)) ||
(src_clk == STM32_SRC_LSE && IS_ENABLED(STM32_LSE_ENABLED)) ||
(src_clk == STM32_SRC_LSI && IS_ENABLED(STM32_LSI_ENABLED)) ||
(src_clk == STM32_SRC_PLL1_P && IS_ENABLED(STM32_PLL_P_ENABLED)) ||
(src_clk == STM32_SRC_PLL2_P && IS_ENABLED(STM32_PLL2_P_ENABLED)) ||
(src_clk == STM32_SRC_PLL2_Q && IS_ENABLED(STM32_PLL2_Q_ENABLED)) ||
(src_clk == STM32_SRC_PLL2_R && IS_ENABLED(STM32_PLL2_R_ENABLED)) ||
(src_clk == STM32_SRC_PLL3_P && IS_ENABLED(STM32_PLL3_P_ENABLED)) ||
(src_clk == STM32_SRC_PLL3_Q && IS_ENABLED(STM32_PLL3_Q_ENABLED)) ||
(src_clk == STM32_SRC_PLL3_R && IS_ENABLED(STM32_PLL3_R_ENABLED)) ||
(src_clk == STM32_SRC_PLL4_P && IS_ENABLED(STM32_PLL4_P_ENABLED)) ||
(src_clk == STM32_SRC_PLL4_Q && IS_ENABLED(STM32_PLL4_Q_ENABLED)) ||
(src_clk == STM32_SRC_PLL4_R && IS_ENABLED(STM32_PLL4_R_ENABLED))) {
return 0;
}

return -ENOTSUP;
}

static int stm32_clock_control_on(const struct device *dev, clock_control_subsys_t sub_system)
{
struct stm32_pclken *pclken = (struct stm32_pclken *)sub_system;
Expand Down Expand Up @@ -57,6 +80,32 @@ static int stm32_clock_control_off(const struct device *dev, clock_control_subsy
return 0;
}

static int stm32_clock_control_configure(const struct device *dev,
clock_control_subsys_t sub_system,
void *data)
{
struct stm32_pclken *pclken = (struct stm32_pclken *)(sub_system);
int err;

ARG_UNUSED(dev);
ARG_UNUSED(data);

err = enabled_clock(pclken->bus);
if (err < 0) {
/* Attempt to configure a src clock not available or not valid */
return err;
}

sys_clear_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_DT_CLKSEL_REG_GET(pclken->enr),
STM32_DT_CLKSEL_MASK_GET(pclken->enr) <<
STM32_DT_CLKSEL_SHIFT_GET(pclken->enr));
sys_set_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_DT_CLKSEL_REG_GET(pclken->enr),
STM32_DT_CLKSEL_VAL_GET(pclken->enr) <<
STM32_DT_CLKSEL_SHIFT_GET(pclken->enr));

return 0;
}

static int stm32_clock_control_get_subsys_rate(const struct device *dev,
clock_control_subsys_t sub_system, uint32_t *rate)
{
Expand Down Expand Up @@ -99,10 +148,37 @@ static int stm32_clock_control_get_subsys_rate(const struct device *dev,
return 0;
}

static enum clock_control_status stm32_clock_control_get_status(const struct device *dev,
clock_control_subsys_t sub_system)
{
struct stm32_pclken *pclken = (struct stm32_pclken *)sub_system;

ARG_UNUSED(dev);

if (IN_RANGE(pclken->bus, STM32_PERIPH_BUS_MIN, STM32_PERIPH_BUS_MAX)) {
/* Gated clocks */
if ((sys_read32(DT_REG_ADDR(DT_NODELABEL(rcc)) + pclken->bus) & pclken->enr)
== pclken->enr) {
return CLOCK_CONTROL_STATUS_ON;
} else {
return CLOCK_CONTROL_STATUS_OFF;
}
} else {
/* Domain clock sources */
if (enabled_clock(pclken->bus) == 0) {
return CLOCK_CONTROL_STATUS_ON;
} else {
return CLOCK_CONTROL_STATUS_OFF;
}
}
}

static DEVICE_API(clock_control, stm32_clock_control_api) = {
.on = stm32_clock_control_on,
.off = stm32_clock_control_off,
.get_rate = stm32_clock_control_get_subsys_rate,
.configure = stm32_clock_control_configure,
.get_status = stm32_clock_control_get_status,
};

static void set_up_fixed_clock_sources(void)
Expand Down Expand Up @@ -173,7 +249,7 @@ static int stm32_clock_control_init(const struct device *dev)
uint32_t pll1_n = DT_PROP(DT_NODELABEL(pll1), mul_n);
uint32_t pll1_m = DT_PROP(DT_NODELABEL(pll1), div_m);
uint32_t pll1_p = DT_PROP(DT_NODELABEL(pll1), div_p);
uint32_t pll1_v = DT_PROP(DT_NODELABEL(pll1), frac_v);
uint32_t pll1_fracn = DT_PROP(DT_NODELABEL(pll1), fracn);

LL_RCC_PLL1_SetN(pll1_n);
while (LL_RCC_PLL1_GetN() != pll1_n) {
Expand All @@ -184,8 +260,8 @@ static int stm32_clock_control_init(const struct device *dev)
LL_RCC_PLL1_SetP(pll1_p);
while (LL_RCC_PLL1_GetP() != pll1_p) {
}
LL_RCC_PLL1_SetFRACV(pll1_v);
while (LL_RCC_PLL1_GetFRACV() != pll1_v) {
LL_RCC_PLL1_SetFRACV(pll1_fracn);
while (LL_RCC_PLL1_GetFRACV() != pll1_fracn) {
}

LL_RCC_PLL1_Enable();
Expand Down
5 changes: 5 additions & 0 deletions drivers/clock_control/clock_stm32_mco.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ static int stm32_mco_init(const struct device *dev)
STM32_DT_CLKSEL_VAL_GET(pclken->enr) <<
STM32_DT_CLKSEL_SHIFT_GET(pclken->enr));

#if defined(MCOX_ON)
sys_set_bits(DT_REG_ADDR(DT_NODELABEL(rcc)) + STM32_DT_CLKSEL_REG_GET(pclken->enr),
MCOX_ON);
#endif

#if defined(HAS_PRESCALER)
/* MCO prescaler */
sys_clear_bits(
Expand Down
30 changes: 30 additions & 0 deletions dts/arm/st/mp13/stm32mp13.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@
};
};

mcos {
mco1: mco1 {
compatible = "st,stm32-clock-mco";
status = "disabled";
};

mco2: mco2 {
compatible = "st,stm32-clock-mco";
status = "disabled";
};
};

soc {
interrupt-parent = <&gic>;

Expand Down Expand Up @@ -278,6 +290,24 @@
compatible = "st,stm32mp13-pll-clock";
status = "disabled";
};

pll2: pll2 {
#clock-cells = <0>;
compatible = "st,stm32mp13-pll-clock";
status = "disabled";
};

pll3: pll3 {
#clock-cells = <0>;
compatible = "st,stm32mp13-pll-clock";
status = "disabled";
};

pll4: pll4 {
#clock-cells = <0>;
compatible = "st,stm32mp13-pll-clock";
status = "disabled";
};
};

timer {
Expand Down
33 changes: 26 additions & 7 deletions dts/bindings/clock/st,stm32mp13-pll-clock.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ description: |
than 1000 MHz or program the mpuss_ck mux to use the MPUDIV
(refer to the stm32mp13 reference manual for details)

div-m (aka DIVM1 + 1), div-p (aka DIVP + 1), div-q (aka DIVQ + 1),
div-r (aka DIVR + 1) have identical valid ranges for all 4 PLLs.
mul-n (aka DIVN + 1) valid range depends on the PLL
PLL1: 31 - 125
PLL2: 25 - 100
PLL3: 25 - 200
PLL4: 25 - 200

compatible: "st,stm32mp13-pll-clock"

include: [clock-controller.yaml, base.yaml]
Expand All @@ -44,25 +52,36 @@ properties:
type: int
required: true
description: |
Prescaler for PLLx
input clock
PLLx division factor (aka DIVM1 + 1) of the input clock divider
Valid range: 1 - 64

mul-n:
type: int
required: true
description: |
PLLx multiplication factor for VCO
Valid range: 31 - 125
PLLx multiplication factor (aka DIVN + 1) for VCO
Valid range: 25 - 200

div-p:
type: int
description: |
PLLx DIVP division factor
PLLx_P division factor (aka DIVP + 1)
Valid range: 1 - 128

div-q:
type: int
description: |
PLLx_Q division factor (aka DIVQ + 1)
Valid range: 1 - 128

div-r:
type: int
description: |
PLLx_R division factor (aka DIVR + 1)
Valid range: 1 - 128

frac-v:
fracn:
type: int
description: |
PLLx FRACV fractional latch
Valid range: 1 - 8192
Valid range: 0 - 8191
23 changes: 20 additions & 3 deletions include/zephyr/drivers/clock_control/stm32_clock_control.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,8 @@
DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32wb_pll_clock, okay) || \
DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32wba_pll_clock, okay) || \
DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32h7_pll_clock, okay) || \
DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32h7rs_pll_clock, okay)
DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32h7rs_pll_clock, okay) || \
DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32mp13_pll_clock, okay)
#define STM32_PLL_ENABLED 1
#define STM32_PLL_M_DIVISOR DT_PROP(DT_NODELABEL(pll), div_m)
#define STM32_PLL_N_MULTIPLIER DT_PROP(DT_NODELABEL(pll), mul_n)
Expand Down Expand Up @@ -215,7 +216,8 @@

#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll2), st_stm32u5_pll_clock, okay) || \
DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll2), st_stm32h7_pll_clock, okay) || \
DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll2), st_stm32h7rs_pll_clock, okay)
DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll2), st_stm32h7rs_pll_clock, okay) || \
DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll2), st_stm32mp13_pll_clock, okay)
#define STM32_PLL2_ENABLED 1
#define STM32_PLL2_M_DIVISOR DT_PROP(DT_NODELABEL(pll2), div_m)
#define STM32_PLL2_N_MULTIPLIER DT_PROP(DT_NODELABEL(pll2), mul_n)
Expand All @@ -235,7 +237,8 @@

#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll3), st_stm32h7_pll_clock, okay) || \
DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll3), st_stm32u5_pll_clock, okay) || \
DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll3), st_stm32h7rs_pll_clock, okay)
DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll3), st_stm32h7rs_pll_clock, okay) || \
DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll3), st_stm32mp13_pll_clock, okay)
#define STM32_PLL3_ENABLED 1
#define STM32_PLL3_M_DIVISOR DT_PROP(DT_NODELABEL(pll3), div_m)
#define STM32_PLL3_N_MULTIPLIER DT_PROP(DT_NODELABEL(pll3), mul_n)
Expand All @@ -251,6 +254,20 @@
#define STM32_PLL3_FRACN_VALUE DT_PROP_OR(DT_NODELABEL(pll3), fracn, 1)
#endif

#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll4), st_stm32mp13_pll_clock, okay)
#define STM32_PLL4_ENABLED 1
#define STM32_PLL4_M_DIVISOR DT_PROP(DT_NODELABEL(pll4), div_m)
#define STM32_PLL4_N_MULTIPLIER DT_PROP(DT_NODELABEL(pll4), mul_n)
#define STM32_PLL4_P_ENABLED DT_NODE_HAS_PROP(DT_NODELABEL(pll4), div_p)
#define STM32_PLL4_P_DIVISOR DT_PROP_OR(DT_NODELABEL(pll4), div_p, 1)
#define STM32_PLL4_Q_ENABLED DT_NODE_HAS_PROP(DT_NODELABEL(pll4), div_q)
#define STM32_PLL4_Q_DIVISOR DT_PROP_OR(DT_NODELABEL(pll4), div_q, 1)
#define STM32_PLL4_R_ENABLED DT_NODE_HAS_PROP(DT_NODELABEL(pll4), div_r)
#define STM32_PLL4_R_DIVISOR DT_PROP_OR(DT_NODELABEL(pll4), div_r, 1)
#define STM32_PLL4_FRACN_ENABLED DT_NODE_HAS_PROP(DT_NODELABEL(pll4), fracn)
#define STM32_PLL4_FRACN_VALUE DT_PROP_OR(DT_NODELABEL(pll4), fracn, 1)
#endif

#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(pll), st_stm32f1_pll_clock, okay)
#define STM32_PLL_ENABLED 1
#define STM32_PLL_XTPRE DT_PROP(DT_NODELABEL(pll), xtpre)
Expand Down
Loading