summaryrefslogtreecommitdiff
path: root/drivers/clk
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/Kconfig13
-rw-r--r--drivers/clk/at91/Makefile1
-rw-r--r--drivers/clk/at91/clk-main.c2
-rw-r--r--drivers/clk/at91/clk-sam9x60-pll.c55
-rw-r--r--drivers/clk/at91/pmc.h2
-rw-r--r--drivers/clk/at91/sam9x60.c7
-rw-r--r--drivers/clk/at91/sam9x7.c1085
-rw-r--r--drivers/clk/at91/sama7g5.c6
-rw-r--r--drivers/clk/clk-uclass.c9
-rw-r--r--drivers/clk/clk_fixed_rate.c1
-rw-r--r--drivers/clk/clk_sandbox.c30
-rw-r--r--drivers/clk/clk_sandbox_ccf.c48
-rw-r--r--drivers/clk/clk_scmi.c62
-rw-r--r--drivers/clk/clk_zynqmp.c20
-rw-r--r--drivers/clk/imx/Kconfig8
-rw-r--r--drivers/clk/imx/Makefile1
-rw-r--r--drivers/clk/imx/clk-fracn-gppll.c1
-rw-r--r--drivers/clk/imx/clk-imx6ul.c289
-rw-r--r--drivers/clk/mediatek/clk-mt7981.c2
-rw-r--r--drivers/clk/mediatek/clk-mt7986.c2
-rw-r--r--drivers/clk/mediatek/clk-mt7987.c2
-rw-r--r--drivers/clk/mediatek/clk-mt7988.c2
-rw-r--r--drivers/clk/mediatek/clk-mtk.c11
-rw-r--r--drivers/clk/mediatek/clk-mtk.h1
-rw-r--r--drivers/clk/qcom/Kconfig24
-rw-r--r--drivers/clk/qcom/Makefile3
-rw-r--r--drivers/clk/qcom/clock-ipq5424.c96
-rw-r--r--drivers/clk/qcom/clock-qcom.h1
-rw-r--r--drivers/clk/qcom/clock-qcs615.c163
-rw-r--r--drivers/clk/qcom/clock-qcs8300.c146
-rw-r--r--drivers/clk/qcom/clock-sc7280.c4
-rw-r--r--drivers/clk/qcom/clock-sm8250.c4
-rw-r--r--drivers/clk/qcom/clock-sm8650.c1
-rw-r--r--drivers/clk/renesas/clk-rcar-gen3.c4
-rw-r--r--drivers/clk/renesas/r8a774a1-cpg-mssr.c2
-rw-r--r--drivers/clk/stm32/Kconfig9
-rw-r--r--drivers/clk/stm32/Makefile1
-rw-r--r--drivers/clk/stm32/clk-stm32-core.c73
-rw-r--r--drivers/clk/stm32/clk-stm32-core.h3
-rw-r--r--drivers/clk/stm32/clk-stm32h7.c5
-rw-r--r--drivers/clk/stm32/clk-stm32mp1.c2
-rw-r--r--drivers/clk/stm32/clk-stm32mp13.c1311
-rw-r--r--drivers/clk/stm32/clk-stm32mp25.c782
-rw-r--r--drivers/clk/stm32/stm32mp13_rcc.h93
44 files changed, 4244 insertions, 143 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 19aa2ffa539..e6483ddc88b 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -10,6 +10,16 @@ config CLK
feed into other clocks in a tree structure, with multiplexers to
choose the source for each clock.
+config CLK_AUTO_ID
+ bool "Enable support of an unique clock id with several provider"
+ depends on CLK
+ help
+ Add the uclass sequence number of clock provider in the 8 higher bits
+ of the clk id to guaranty an unique clock identifier in clk uclass
+ when several clock providers are present on the device and when
+ default xlate are used.
+ This feature limit each identifier for each clock providers (24 bits).
+
config SPL_CLK
bool "Enable clock support in SPL"
depends on CLK && SPL && SPL_DM
@@ -182,6 +192,7 @@ config CLK_SCMI
bool "Enable SCMI clock driver"
depends on CLK
depends on SCMI_FIRMWARE
+ select CLK_AUTO_ID if CLK_CCF
help
Enable this option if you want to support clock devices exposed
by a SCMI agent based on SCMI clock protocol communication
@@ -214,7 +225,7 @@ config CLK_VERSACLOCK
config CLK_VERSAL
bool "Enable clock driver support for Versal"
depends on (ARCH_VERSAL || ARCH_VERSAL_NET)
- imply ZYNQMP_FIRMWARE
+ depends on ZYNQMP_FIRMWARE
help
This clock driver adds support for clock realted settings for
Versal platform.
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
index e53dcb4ca7a..6cca861f81c 100644
--- a/drivers/clk/at91/Makefile
+++ b/drivers/clk/at91/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o
obj-$(CONFIG_AT91_SAM9X60_USB) += clk-sam9x60-usb.o
obj-$(CONFIG_SAMA7G5) += sama7g5.o
obj-$(CONFIG_SAM9X60) += sam9x60.o
+obj-$(CONFIG_SAM9X7) += sam9x7.o
else
obj-y += compat.o
endif
diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
index 09daae97676..a5186f885f0 100644
--- a/drivers/clk/at91/clk-main.c
+++ b/drivers/clk/at91/clk-main.c
@@ -110,7 +110,7 @@ struct clk *at91_clk_main_rc(void __iomem *reg, const char *name,
struct clk *clk;
int ret;
- if (!reg || !name || !parent_name)
+ if (!reg || !name)
return ERR_PTR(-EINVAL);
main_rc = kzalloc(sizeof(*main_rc), GFP_KERNEL);
diff --git a/drivers/clk/at91/clk-sam9x60-pll.c b/drivers/clk/at91/clk-sam9x60-pll.c
index a30035eb8ce..df8172bccac 100644
--- a/drivers/clk/at91/clk-sam9x60-pll.c
+++ b/drivers/clk/at91/clk-sam9x60-pll.c
@@ -22,6 +22,7 @@
#define UBOOT_DM_CLK_AT91_SAM9X60_DIV_PLL "at91-sam9x60-div-pll-clk"
#define UBOOT_DM_CLK_AT91_SAM9X60_FRAC_PLL "at91-sam9x60-frac-pll-clk"
+#define UBOOT_DM_CLK_AT91_SAM9X60_FIXED_DIV_PLL "at91-sam9x60-fixed-div-pll-clk"
#define PMC_PLL_CTRL0_DIV_MSK GENMASK(7, 0)
#define PMC_PLL_CTRL1_MUL_MSK GENMASK(31, 24)
@@ -31,9 +32,6 @@
#define UPLL_DIV 2
#define PLL_MUL_MAX (FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1)
-#define FCORE_MIN (600000000)
-#define FCORE_MAX (1200000000)
-
#define PLL_MAX_ID 7
struct sam9x60_pll {
@@ -55,14 +53,15 @@ static inline bool sam9x60_pll_ready(void __iomem *base, int id)
return !!(status & BIT(id));
}
-static long sam9x60_frac_pll_compute_mul_frac(u32 *mul, u32 *frac, ulong rate,
+static long sam9x60_frac_pll_compute_mul_frac(const struct clk_range *core_clk,
+ u32 *mul, u32 *frac, ulong rate,
ulong parent_rate)
{
unsigned long tmprate, remainder;
unsigned long nmul = 0;
unsigned long nfrac = 0;
- if (rate < FCORE_MIN || rate > FCORE_MAX)
+ if (rate < core_clk->min || rate > core_clk->max)
return -ERANGE;
/*
@@ -82,7 +81,7 @@ static long sam9x60_frac_pll_compute_mul_frac(u32 *mul, u32 *frac, ulong rate,
}
/* Check if resulted rate is valid. */
- if (tmprate < FCORE_MIN || tmprate > FCORE_MAX)
+ if (tmprate < core_clk[0].min || tmprate > core_clk[0].max)
return -ERANGE;
*mul = nmul - 1;
@@ -103,8 +102,8 @@ static ulong sam9x60_frac_pll_set_rate(struct clk *clk, ulong rate)
if (!parent_rate)
return 0;
- ret = sam9x60_frac_pll_compute_mul_frac(&nmul, &nfrac, rate,
- parent_rate);
+ ret = sam9x60_frac_pll_compute_mul_frac(pll->characteristics->core_output,
+ &nmul, &nfrac, rate, parent_rate);
if (ret < 0)
return 0;
@@ -142,6 +141,7 @@ static ulong sam9x60_frac_pll_get_rate(struct clk *clk)
void __iomem *base = pll->base;
ulong parent_rate = clk_get_parent_rate(clk);
u32 mul, frac, val;
+ ulong pll_rate;
if (!parent_rate)
return 0;
@@ -151,8 +151,12 @@ static ulong sam9x60_frac_pll_get_rate(struct clk *clk)
pmc_read(base, AT91_PMC_PLL_CTRL1, &val);
mul = (val & pll->layout->mul_mask) >> pll->layout->mul_shift;
frac = (val & pll->layout->frac_mask) >> pll->layout->frac_shift;
+ pll_rate = (parent_rate * (mul + 1) + ((u64)parent_rate * frac >> 22));
+
+ if (pll->layout->div2)
+ pll_rate >>= 1;
- return (parent_rate * (mul + 1) + ((u64)parent_rate * frac >> 22));
+ return pll_rate;
}
static int sam9x60_frac_pll_enable(struct clk *clk)
@@ -163,7 +167,8 @@ static int sam9x60_frac_pll_enable(struct clk *clk)
ulong crate;
crate = sam9x60_frac_pll_get_rate(clk);
- if (crate < FCORE_MIN || crate > FCORE_MAX)
+ if (crate < pll->characteristics->core_output[0].min ||
+ crate > pll->characteristics->core_output[0].max)
return -ERANGE;
pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
@@ -360,6 +365,16 @@ static ulong sam9x60_div_pll_get_rate(struct clk *clk)
return parent_rate / (div + 1);
}
+static ulong sam9x60_fixed_div_pll_get_rate(struct clk *clk)
+{
+ ulong parent_rate = clk_get_parent_rate(clk);
+
+ if (!parent_rate)
+ return 0;
+
+ return parent_rate >> 1;
+}
+
static const struct clk_ops sam9x60_div_pll_ops = {
.enable = sam9x60_div_pll_enable,
.disable = sam9x60_div_pll_disable,
@@ -367,6 +382,12 @@ static const struct clk_ops sam9x60_div_pll_ops = {
.get_rate = sam9x60_div_pll_get_rate,
};
+static const struct clk_ops sam9x60_fixed_div_pll_ops = {
+ .enable = sam9x60_div_pll_enable,
+ .disable = sam9x60_div_pll_disable,
+ .get_rate = sam9x60_fixed_div_pll_get_rate,
+};
+
static struct clk *
sam9x60_clk_register_pll(void __iomem *base, const char *type,
const char *name, const char *parent_name, u8 id,
@@ -407,6 +428,13 @@ sam9x60_clk_register_div_pll(void __iomem *base, const char *name,
const struct clk_pll_characteristics *characteristics,
const struct clk_pll_layout *layout, bool critical)
{
+ if (layout->div2) {
+ return sam9x60_clk_register_pll(base,
+ UBOOT_DM_CLK_AT91_SAM9X60_FIXED_DIV_PLL, name, parent_name,
+ id, characteristics, layout,
+ CLK_GET_RATE_NOCACHE | (critical ? CLK_IS_CRITICAL : 0));
+ }
+
return sam9x60_clk_register_pll(base,
UBOOT_DM_CLK_AT91_SAM9X60_DIV_PLL, name, parent_name, id,
characteristics, layout,
@@ -432,6 +460,13 @@ U_BOOT_DRIVER(at91_sam9x60_div_pll_clk) = {
.flags = DM_FLAG_PRE_RELOC,
};
+U_BOOT_DRIVER(at91_sam9x60_fixed_div_pll_clk) = {
+ .name = UBOOT_DM_CLK_AT91_SAM9X60_FIXED_DIV_PLL,
+ .id = UCLASS_CLK,
+ .ops = &sam9x60_fixed_div_pll_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
U_BOOT_DRIVER(at91_sam9x60_frac_pll_clk) = {
.name = UBOOT_DM_CLK_AT91_SAM9X60_FRAC_PLL,
.id = UCLASS_CLK,
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index ff464522aa0..580c9964ff4 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -38,6 +38,7 @@ struct clk_pll_characteristics {
struct clk_range input;
int num_output;
const struct clk_range *output;
+ const struct clk_range *core_output;
u16 *icpll;
u8 *out;
u8 upll : 1;
@@ -53,6 +54,7 @@ struct clk_pll_layout {
u8 frac_shift;
u8 div_shift;
u8 endiv_shift;
+ u8 div2;
};
struct clk_programmable_layout {
diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c
index b7d64bdbb3d..e04266a2be2 100644
--- a/drivers/clk/at91/sam9x60.c
+++ b/drivers/clk/at91/sam9x60.c
@@ -112,17 +112,24 @@ static const struct clk_range upll_outputs[] = {
{ .min = 300000000, .max = 500000000 },
};
+/* Fractional PLL core output range. */
+static const struct clk_range core_outputs[] = {
+ { .min = 600000000, .max = 1200000000 },
+};
+
/* PLL characteristics. */
static const struct clk_pll_characteristics apll_characteristics = {
.input = { .min = 12000000, .max = 48000000 },
.num_output = ARRAY_SIZE(plla_outputs),
.output = plla_outputs,
+ .core_output = core_outputs,
};
static const struct clk_pll_characteristics upll_characteristics = {
.input = { .min = 12000000, .max = 48000000 },
.num_output = ARRAY_SIZE(upll_outputs),
.output = upll_outputs,
+ .core_output = core_outputs,
.upll = true,
};
diff --git a/drivers/clk/at91/sam9x7.c b/drivers/clk/at91/sam9x7.c
new file mode 100644
index 00000000000..ad9865feff0
--- /dev/null
+++ b/drivers/clk/at91/sam9x7.c
@@ -0,0 +1,1085 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Varshini Rajendran <varshini.rajendran@microchip.com>
+ *
+ */
+
+#include <clk-uclass.h>
+#include <dm.h>
+#include <dt-bindings/clock/at91.h>
+#include <linux/clk-provider.h>
+
+#include "pmc.h"
+
+/**
+ * Clock identifiers to be used in conjunction with macros like
+ * AT91_TO_CLK_ID()
+ *
+ * @ID_MD_SLCK: TD slow clock identifier
+ * @ID_TD_SLCK: MD slow clock identifier
+ * @ID_MAIN_XTAL: Main Xtal clock identifier
+ * @ID_MAIN_RC: Main RC clock identifier
+ * @ID_MAIN_RC_OSC: Main RC Oscillator clock identifier
+ * @ID_MAIN_OSC: Main Oscillator clock identifier
+ * @ID_MAINCK: MAINCK clock identifier
+ * @ID_PLL_U_FRAC: UPLL fractional clock identifier
+ * @ID_PLL_U_DIV: UPLL divider clock identifier
+ * @ID_PLL_A_FRAC: APLL fractional clock identifier
+ * @ID_PLL_A_DIV: APLL divider clock identifier
+ * @ID_PLL_A_2_DIV: PLLA DIV2 divider clock identifier
+ * @ID_PLL_AUDIO_FRAC: Audio PLL fractional clock identifier
+ * @ID_PLL_AUDIO_DIVPMC: Audio PLL divider clock identifier
+ * @ID_PLL_AUDIO_DIVIO: Audio PLL IO divider clock identifier
+ * @ID_PLL_LVDS_FRAC: LVDS PLL fractional clock identifier
+ * @ID_PLL_LVDS_DIV: LVDS PLL divider clock identifier
+
+ * @ID_MCK_DIV: MCK DIV clock identifier
+
+ * @ID_UTMI: UTMI clock identifier
+
+ * @ID_PROG0: Programmable 0 clock identifier
+ * @ID_PROG1: Programmable 1 clock identifier
+
+ * @ID_PCK0: PCK0 system clock identifier
+ * @ID_PCK1: PCK1 system clock identifier
+ * @ID_DDR: DDR system clock identifier
+ * @ID_QSPI: QSPI system clock identifier
+ *
+ * @ID_MCK_PRES: MCK PRES clock identifier
+ *
+ * Note: if changing the values of this enums please sync them with
+ * device tree
+ */
+enum pmc_clk_ids {
+ ID_MD_SLCK = 0,
+ ID_TD_SLCK = 1,
+ ID_MAIN_XTAL = 2,
+ ID_MAIN_RC = 3,
+ ID_MAIN_RC_OSC = 4,
+ ID_MAIN_OSC = 5,
+ ID_MAINCK = 6,
+
+ ID_PLL_U_FRAC = 7,
+ ID_PLL_U_DIV = 8,
+ ID_PLL_A_FRAC = 9,
+ ID_PLL_A_DIV = 10,
+ ID_PLL_A_2_DIV = 11,
+ ID_PLL_AUDIO_FRAC = 12,
+ ID_PLL_AUDIO_DIVPMC = 13,
+ ID_PLL_AUDIO_DIVIO = 14,
+ ID_PLL_LVDS_FRAC = 15,
+ ID_PLL_LVDS_DIV = 16,
+
+ ID_MCK_DIV = 17,
+
+ ID_UTMI = 18,
+
+ ID_PROG0 = 19,
+ ID_PROG1 = 20,
+
+ ID_PCK0 = 21,
+ ID_PCK1 = 22,
+
+ ID_DDR = 23,
+ ID_QSPI = 24,
+
+ ID_MCK_PRES = 25,
+
+ ID_MAX,
+};
+
+/**
+ * PLL type identifiers
+ * @PLL_TYPE_FRAC: fractional PLL identifier
+ * @PLL_TYPE_DIV: divider PLL identifier
+ */
+enum pll_type {
+ PLL_TYPE_FRAC,
+ PLL_TYPE_DIV,
+};
+
+/* Clock names used as parents for multiple clocks. */
+static const char *clk_names[] = {
+ [ID_MAIN_RC] = "main_rc",
+ [ID_MAIN_RC_OSC] = "main_rc_osc",
+ [ID_MAIN_OSC] = "main_osc",
+ [ID_MAINCK] = "mainck",
+ [ID_PLL_U_DIV] = "upll_divpmcck",
+ [ID_PLL_A_DIV] = "plla_divpmcck",
+ [ID_PLL_A_2_DIV] = "plla_div2pmcck",
+ [ID_PLL_AUDIO_DIVPMC] = "pll_audio_divpmcck",
+ [ID_PLL_AUDIO_DIVIO] = "pll_audio_diviock",
+ [ID_PLL_LVDS_DIV] = "pll_lvds_divpmcck",
+ [ID_MCK_PRES] = "mck_pres",
+ [ID_MCK_DIV] = "mck_div",
+};
+
+/* Fractional PLL core output range. */
+static const struct clk_range plla_core_outputs[] = {
+ { .min = 800000000, .max = 1600000000 },
+};
+
+static const struct clk_range upll_core_outputs[] = {
+ { .min = 600000000, .max = 960000000 },
+};
+
+static const struct clk_range lvdspll_core_outputs[] = {
+ { .min = 600000000, .max = 1200000000 },
+};
+
+static const struct clk_range audiopll_core_outputs[] = {
+ { .min = 600000000, .max = 1200000000 },
+};
+
+static const struct clk_range plladiv2_core_outputs[] = {
+ { .min = 800000000, .max = 1600000000 },
+};
+
+/* Fractional PLL output range. */
+static const struct clk_range plla_outputs[] = {
+ { .min = 400000000, .max = 800000000 },
+};
+
+static const struct clk_range upll_outputs[] = {
+ { .min = 300000000, .max = 480000000 },
+};
+
+static const struct clk_range lvdspll_outputs[] = {
+ { .min = 175000000, .max = 550000000 },
+};
+
+static const struct clk_range audiopll_outputs[] = {
+ { .min = 0, .max = 300000000 },
+};
+
+static const struct clk_range plladiv2_outputs[] = {
+ { .min = 200000000, .max = 400000000 },
+};
+
+/* PLL characteristics. */
+static const struct clk_pll_characteristics plla_characteristics = {
+ .input = { .min = 20000000, .max = 50000000 },
+ .num_output = ARRAY_SIZE(plla_outputs),
+ .output = plla_outputs,
+ .core_output = plla_core_outputs,
+};
+
+static const struct clk_pll_characteristics upll_characteristics = {
+ .input = { .min = 20000000, .max = 50000000 },
+ .num_output = ARRAY_SIZE(upll_outputs),
+ .output = upll_outputs,
+ .core_output = upll_core_outputs,
+ .upll = true,
+};
+
+static const struct clk_pll_characteristics lvdspll_characteristics = {
+ .input = { .min = 20000000, .max = 50000000 },
+ .num_output = ARRAY_SIZE(lvdspll_outputs),
+ .output = lvdspll_outputs,
+ .core_output = lvdspll_core_outputs,
+};
+
+static const struct clk_pll_characteristics audiopll_characteristics = {
+ .input = { .min = 20000000, .max = 50000000 },
+ .num_output = ARRAY_SIZE(audiopll_outputs),
+ .output = audiopll_outputs,
+ .core_output = audiopll_core_outputs,
+};
+
+static const struct clk_pll_characteristics plladiv2_characteristics = {
+ .input = { .min = 20000000, .max = 50000000 },
+ .num_output = ARRAY_SIZE(plladiv2_outputs),
+ .output = plladiv2_outputs,
+ .core_output = plladiv2_core_outputs,
+};
+
+/* Layout for fractional PLLs. */
+static const struct clk_pll_layout pll_layout_frac = {
+ .mul_mask = GENMASK(31, 24),
+ .frac_mask = GENMASK(21, 0),
+ .mul_shift = 24,
+ .frac_shift = 0,
+};
+
+/* Layout for fractional PLL ID PLLA. */
+static const struct clk_pll_layout plla_layout_frac = {
+ .mul_mask = GENMASK(31, 24),
+ .frac_mask = GENMASK(21, 0),
+ .mul_shift = 24,
+ .frac_shift = 0,
+ .div2 = 1,
+};
+
+/* Layout for DIV PLLs. */
+static const struct clk_pll_layout pll_layout_divpmc = {
+ .div_mask = GENMASK(7, 0),
+ .endiv_mask = BIT(29),
+ .div_shift = 0,
+ .endiv_shift = 29,
+};
+
+/* Layout for DIV PLLs. */
+static const struct clk_pll_layout plladiv2_layout_divpmc = {
+ .div_mask = GENMASK(7, 0),
+ .endiv_mask = BIT(29),
+ .div_shift = 0,
+ .endiv_shift = 29,
+ .div2 = 1,
+};
+
+/* Layout for DIVIO dividers. */
+static const struct clk_pll_layout pll_layout_divio = {
+ .div_mask = GENMASK(19, 12),
+ .endiv_mask = BIT(30),
+ .div_shift = 12,
+ .endiv_shift = 30,
+};
+
+/* MCK characteristics. */
+static const struct clk_master_characteristics mck_characteristics = {
+ .output = { .min = 32000000, .max = 266666666 },
+ .divisors = { 1, 2, 4, 3, 5},
+ .have_div3_pres = 1,
+};
+
+/* MCK layout. */
+static const struct clk_master_layout mck_layout = {
+ .mask = 0x373,
+ .pres_shift = 4,
+ .offset = 0x28,
+};
+
+/* Programmable clock layout. */
+static const struct clk_programmable_layout programmable_layout = {
+ .pres_mask = 0xff,
+ .pres_shift = 8,
+ .css_mask = 0x1f,
+ .have_slck_mck = 0,
+ .is_pres_direct = 1,
+};
+
+/* Peripheral clock layout. */
+static const struct clk_pcr_layout sam9x7_pcr_layout = {
+ .offset = 0x88,
+ .cmd = BIT(31),
+ .gckcss_mask = GENMASK(12, 8),
+ .pid_mask = GENMASK(6, 0),
+};
+
+/**
+ * PLL clocks description
+ * @n: clock name
+ * @p: clock parent
+ * @l: clock layout
+ * @t: clock type
+ * @c: pll characteristics
+ * @f: true if clock is fixed and not changeable by driver
+ * @id: clock id corresponding to PLL driver
+ * @cid: clock id corresponding to clock subsystem
+ */
+static const struct {
+ const char *n;
+ const char *p;
+ const struct clk_pll_layout *l;
+ const struct clk_pll_characteristics *c;
+ u8 t;
+ u8 f;
+ u8 id;
+ u8 cid;
+} sam9x7_plls[] = {
+ {
+ .n = "plla_fracck",
+ .p = "mainck",
+ .l = &plla_layout_frac,
+ .c = &plla_characteristics,
+ .t = PLL_TYPE_FRAC,
+ .f = 1,
+ .id = 0,
+ .cid = ID_PLL_A_FRAC,
+ },
+
+ {
+ .n = "plla_divpmcck",
+ .p = "plla_fracck",
+ .l = &pll_layout_divpmc,
+ .c = &plla_characteristics,
+ .t = PLL_TYPE_DIV,
+ .f = 1,
+ .id = 0,
+ .cid = ID_PLL_A_DIV,
+ },
+
+ {
+ .n = "upll_fracck",
+ .p = "main_osc",
+ .l = &pll_layout_frac,
+ .c = &upll_characteristics,
+ .t = PLL_TYPE_FRAC,
+ .f = 1,
+ .id = 1,
+ .cid = ID_PLL_U_FRAC,
+ },
+
+ {
+ .n = "upll_divpmcck",
+ .p = "upll_fracck",
+ .l = &pll_layout_divpmc,
+ .c = &upll_characteristics,
+ .t = PLL_TYPE_DIV,
+ .f = 1,
+ .id = 1,
+ .cid = ID_PLL_U_DIV,
+ },
+
+ {
+ .n = "audiopll_fracck",
+ .p = "main_osc",
+ .l = &pll_layout_frac,
+ .c = &audiopll_characteristics,
+ .t = PLL_TYPE_FRAC,
+ .f = 1,
+ .id = 2,
+ .cid = ID_PLL_AUDIO_FRAC,
+ },
+
+ {
+ .n = "audiopll_divpmcck",
+ .p = "audiopll_fracck",
+ .l = &pll_layout_divpmc,
+ .c = &audiopll_characteristics,
+ .t = PLL_TYPE_DIV,
+ .f = 1,
+ .id = 2,
+ .cid = ID_PLL_AUDIO_DIVPMC,
+ },
+
+ {
+ .n = "audiopll_diviock",
+ .p = "audiopll_fracck",
+ .l = &pll_layout_divio,
+ .c = &audiopll_characteristics,
+ .t = PLL_TYPE_DIV,
+ .f = 1,
+ .id = 2,
+ .cid = ID_PLL_AUDIO_DIVIO,
+ },
+
+ {
+ .n = "lvdspll_fracck",
+ .p = "main_osc",
+ .l = &pll_layout_frac,
+ .c = &lvdspll_characteristics,
+ .t = PLL_TYPE_FRAC,
+ .f = 1,
+ .id = 3,
+ .cid = ID_PLL_LVDS_FRAC,
+ },
+
+ {
+ .n = "lvdspll_divpmcck",
+ .p = "lvdspll_fracck",
+ .l = &pll_layout_divpmc,
+ .c = &lvdspll_characteristics,
+ .t = PLL_TYPE_DIV,
+ .f = 1,
+ .id = 3,
+ .cid = ID_PLL_LVDS_DIV,
+ },
+
+ {
+ .n = "plla_div2pmcck",
+ .p = "plla_fracck",
+ .l = &plladiv2_layout_divpmc,
+ .c = &plladiv2_characteristics,
+ .t = PLL_TYPE_DIV,
+ .f = 1,
+ .id = 4,
+ .cid = ID_PLL_A_2_DIV,
+ },
+
+};
+
+/**
+ * Programmable clock description
+ * @n: clock name
+ * @cid: clock id corresponding to clock subsystem
+ */
+static const struct {
+ const char *n;
+ u8 cid;
+} sam9x7_prog[] = {
+ { .n = "prog0", .cid = ID_PROG0, },
+ { .n = "prog1", .cid = ID_PROG1, },
+};
+
+/* Mux table for programmable clocks. */
+static u32 sam9x7_prog_mux_table[] = { 0, 1, 2, 3, 4, 5, 6, };
+
+/**
+ * System clock description
+ * @n: clock name
+ * @p: parent clock name
+ * @id: clock id corresponding to system clock driver
+ * @cid: clock id corresponding to clock subsystem
+ */
+static const struct {
+ const char *n;
+ const char *p;
+ u8 id;
+ u8 cid;
+} sam9x7_systemck[] = {
+ { .n = "ddrck", .p = "mck_pres", .id = 2, .cid = ID_DDR, },
+ { .n = "pck0", .p = "prog0", .id = 8, .cid = ID_PCK0, },
+ { .n = "pck1", .p = "prog1", .id = 9, .cid = ID_PCK1, },
+};
+
+/**
+ * Peripheral clock description
+ * @n: clock name
+ * @id: clock id
+ */
+static const struct {
+ const char *n;
+ u8 id;
+} sam9x7_periphck[] = {
+ { .n = "pioA_clk", .id = 2, },
+ { .n = "pioB_clk", .id = 3, },
+ { .n = "pioC_clk", .id = 4, },
+ { .n = "flex0_clk", .id = 5, },
+ { .n = "flex1_clk", .id = 6, },
+ { .n = "flex2_clk", .id = 7, },
+ { .n = "flex3_clk", .id = 8, },
+ { .n = "flex6_clk", .id = 9, },
+ { .n = "flex7_clk", .id = 10, },
+ { .n = "flex8_clk", .id = 11, },
+ { .n = "sdmmc0_clk", .id = 12, },
+ { .n = "flex4_clk", .id = 13, },
+ { .n = "flex5_clk", .id = 14, },
+ { .n = "flex9_clk", .id = 15, },
+ { .n = "flex10_clk", .id = 16, },
+ { .n = "tcb0_clk", .id = 17, },
+ { .n = "pwm_clk", .id = 18, },
+ { .n = "adc_clk", .id = 19, },
+ { .n = "dma0_clk", .id = 20, },
+ { .n = "uhphs_clk", .id = 22, },
+ { .n = "udphs_clk", .id = 23, },
+ { .n = "gmac_clk", .id = 24, },
+ { .n = "lcd_clk", .id = 25, },
+ { .n = "sdmmc1_clk", .id = 26, },
+ { .n = "ssc_clk", .id = 28, },
+ { .n = "mcan0_clk", .id = 29, },
+ { .n = "mcan1_clk", .id = 30, },
+ { .n = "flex11_clk", .id = 32, },
+ { .n = "flex12_clk", .id = 33, },
+ { .n = "i2s_clk", .id = 34, },
+ { .n = "qspi_clk", .id = 35, },
+ { .n = "gfx2d_clk", .id = 36, },
+ { .n = "pit64b0_clk", .id = 37, },
+ { .n = "trng_clk", .id = 38, },
+ { .n = "aes_clk", .id = 39, },
+ { .n = "tdes_clk", .id = 40, },
+ { .n = "sha_clk", .id = 41, },
+ { .n = "classd_clk", .id = 42, },
+ { .n = "isi_clk", .id = 43, },
+ { .n = "pioD_clk", .id = 44, },
+ { .n = "tcb1_clk", .id = 45, },
+ { .n = "dbgu_clk", .id = 47, },
+ { .n = "pmecc_clk", .id = 48, },
+ { .n = "mpddr_clk", .id = 49, },
+ { .n = "csi2dc_clk", .id = 52, },
+ { .n = "csi4l_clk", .id = 53, },
+ { .n = "dsi4l_clk", .id = 54, },
+ { .n = "lvdsc_clk", .id = 56, },
+ { .n = "pit64b1_clk", .id = 58, },
+ { .n = "puf_clk", .id = 59, },
+ { .n = "gmactsu_clk", .id = 67, },
+};
+
+/**
+ * Generic clock description
+ * @n: clock name
+ * @ep: extra parents names
+ * @ep_mux_table: extra parents mux table
+ * @ep_clk_mux_table: extra parents clock mux table (for CCF)
+ * @r: clock output range
+ * @ep_count: extra parents count
+ * @id: clock id
+ */
+static const struct {
+ const char *n;
+ const char *ep[8];
+ const char ep_mux_table[8];
+ const char ep_clk_mux_table[8];
+ struct clk_range r;
+ u8 ep_count;
+ u8 id;
+} sam9x7_gck[] = {
+ {
+ .n = "flex0_gclk",
+ .id = 5,
+ .ep = { "plla_div2pmcck", },
+ .ep_mux_table = { 8, },
+ .ep_clk_mux_table = { ID_PLL_A_2_DIV, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "flex1_gclk",
+ .id = 6,
+ .ep = { "plla_div2pmcck", },
+ .ep_mux_table = { 8, },
+ .ep_clk_mux_table = { ID_PLL_A_2_DIV, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "flex2_gclk",
+ .id = 7,
+ .ep = { "plla_div2pmcck", },
+ .ep_mux_table = { 8, },
+ .ep_clk_mux_table = { ID_PLL_A_2_DIV, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "flex3_gclk",
+ .id = 8,
+ .ep = { "plla_div2pmcck", },
+ .ep_mux_table = { 8, },
+ .ep_clk_mux_table = { ID_PLL_A_2_DIV, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "flex6_gclk",
+ .id = 9,
+ .ep = { "plla_div2pmcck", },
+ .ep_mux_table = { 8, },
+ .ep_clk_mux_table = { ID_PLL_A_2_DIV, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "flex7_gclk",
+ .id = 10,
+ .ep = { "plla_div2pmcck", },
+ .ep_mux_table = { 8, },
+ .ep_clk_mux_table = { ID_PLL_A_2_DIV, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "flex8_gclk",
+ .id = 11,
+ .ep = { "plla_div2pmcck", },
+ .ep_mux_table = { 8, },
+ .ep_clk_mux_table = { ID_PLL_A_2_DIV, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "sdmmc0_gclk",
+ .id = 12,
+ .r = { .max = 105000000 },
+ .ep = { "audiopll_divpmcck", "plla_div2pmcck", },
+ .ep_mux_table = { 6, 8, },
+ .ep_clk_mux_table = { ID_PLL_AUDIO_DIVPMC, ID_PLL_A_2_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex4_gclk",
+ .id = 13,
+ .ep = { "plla_div2pmcck", },
+ .ep_mux_table = { 8, },
+ .ep_clk_mux_table = { ID_PLL_A_2_DIV, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "flex5_gclk",
+ .id = 14,
+ .ep = { "plla_div2pmcck", },
+ .ep_mux_table = { 8, },
+ .ep_clk_mux_table = { ID_PLL_A_2_DIV, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "flex9_gclk",
+ .id = 15,
+ .ep = { "plla_div2pmcck", },
+ .ep_mux_table = { 8, },
+ .ep_clk_mux_table = { ID_PLL_A_2_DIV, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "flex10_gclk",
+ .id = 16,
+ .ep = { "plla_div2pmcck", },
+ .ep_mux_table = { 8, },
+ .ep_clk_mux_table = { ID_PLL_A_2_DIV, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "tcb0_gclk",
+ .id = 17,
+ .ep = { "audiopll_divpmcck", "plla_div2pmcck", },
+ .ep_mux_table = { 6, 8, },
+ .ep_clk_mux_table = { ID_PLL_AUDIO_DIVPMC, ID_PLL_A_2_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "adc_gclk",
+ .id = 19,
+ .ep = { "upll_divpmcck", "plla_div2pmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_U_DIV, ID_PLL_A_2_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "gmac_gclk",
+ .id = 24,
+ .ep = { "audiopll_divpmcck", "plla_div2pmcck", },
+ .ep_mux_table = { 6, 8, },
+ .ep_clk_mux_table = { ID_PLL_AUDIO_DIVPMC, ID_PLL_A_2_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "lcd_gclk",
+ .id = 25,
+ .r = { .max = 75000000 },
+ .ep = { "audiopll_divpmcck", "plla_div2pmcck", },
+ .ep_mux_table = { 6, 8, },
+ .ep_clk_mux_table = { ID_PLL_AUDIO_DIVPMC, ID_PLL_A_2_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "sdmmc1_gclk",
+ .id = 26,
+ .r = { .max = 105000000 },
+ .ep = { "audiopll_divpmcck", "plla_div2pmcck", },
+ .ep_mux_table = { 6, 8, },
+ .ep_clk_mux_table = { ID_PLL_AUDIO_DIVPMC, ID_PLL_A_2_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "mcan0_gclk",
+ .id = 29,
+ .r = { .max = 80000000 },
+ .ep = { "upll_divpmcck", "plla_div2pmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_U_DIV, ID_PLL_A_2_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "mcan1_gclk",
+ .id = 30,
+ .r = { .max = 80000000 },
+ .ep = { "upll_divpmcck", "plla_div2pmcck", },
+ .ep_mux_table = { 5, 8, },
+ .ep_clk_mux_table = { ID_PLL_U_DIV, ID_PLL_A_2_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "flex11_gclk",
+ .id = 32,
+ .ep = { "plla_div2pmcck", },
+ .ep_mux_table = { 8, },
+ .ep_clk_mux_table = { ID_PLL_A_2_DIV, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "flex12_gclk",
+ .id = 33,
+ .ep = { "plla_div2pmcck", },
+ .ep_mux_table = { 8, },
+ .ep_clk_mux_table = { ID_PLL_A_2_DIV, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "i2s_gclk",
+ .id = 34,
+ .r = { .max = 100000000 },
+ .ep = { "audiopll_divpmcck", "plla_div2pmcck", },
+ .ep_mux_table = { 6, 8, },
+ .ep_clk_mux_table = { ID_PLL_AUDIO_DIVPMC, ID_PLL_A_2_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "qspi_gclk",
+ .id = 35,
+ .r = { .max = 200000000 },
+ .ep = { "audiopll_divpmcck", "plla_div2pmcck", },
+ .ep_mux_table = { 6, 8, },
+ .ep_clk_mux_table = { ID_PLL_AUDIO_DIVPMC, ID_PLL_A_2_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "pit64b0_gclk",
+ .id = 37,
+ .ep = { "plla_div2pmcck", },
+ .ep_mux_table = { 8, },
+ .ep_clk_mux_table = { ID_PLL_A_2_DIV, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "classd_gclk",
+ .id = 42,
+ .r = { .max = 100000000 },
+ .ep = { "audiopll_divpmcck", "plla_div2pmcck", },
+ .ep_mux_table = { 6, 8, },
+ .ep_clk_mux_table = { ID_PLL_AUDIO_DIVPMC, ID_PLL_A_2_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "tcb1_gclk",
+ .id = 45,
+ .ep = { "audiopll_divpmcck", "plla_div2pmcck", },
+ .ep_mux_table = { 6, 8, },
+ .ep_clk_mux_table = { ID_PLL_AUDIO_DIVPMC, ID_PLL_A_2_DIV, },
+ .ep_count = 2,
+ },
+
+ {
+ .n = "dbgu_gclk",
+ .id = 47,
+ .ep = { "plla_div2pmcck", },
+ .ep_mux_table = { 8, },
+ .ep_clk_mux_table = { ID_PLL_A_2_DIV, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "mipiphy_gclk",
+ .id = 55,
+ .r = { .max = 27000000 },
+ .ep = { "plla_div2pmcck", },
+ .ep_mux_table = { 8, },
+ .ep_clk_mux_table = { ID_PLL_A_2_DIV, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "pit64b1_gclk",
+ .id = 58,
+ .ep = { "plla_div2pmcck", },
+ .ep_mux_table = { 8, },
+ .ep_clk_mux_table = { ID_PLL_A_2_DIV, },
+ .ep_count = 1,
+ },
+
+ {
+ .n = "gmac_tsu_gclk",
+ .id = 67,
+ .ep = { "audiopll_divpmcck", "plla_div2pmcck", },
+ .ep_mux_table = { 6, 8, },
+ .ep_clk_mux_table = { ID_PLL_AUDIO_DIVPMC, ID_PLL_A_2_DIV, },
+ .ep_count = 2,
+ },
+
+};
+
+#define prepare_mux_table(_allocs, _index, _dst, _src, _num, _label) \
+ do { \
+ int _i; \
+ (_dst) = kzalloc(sizeof(*(_dst)) * (_num), GFP_KERNEL); \
+ if (!(_dst)) { \
+ ret = -ENOMEM; \
+ goto _label; \
+ } \
+ (_allocs)[(_index)++] = (_dst); \
+ for (_i = 0; _i < (_num); _i++) \
+ (_dst)[_i] = (_src)[_i]; \
+ } while (0)
+
+static int sam9x7_clk_probe(struct udevice *dev)
+{
+ void __iomem *base = (void *)devfdt_get_addr_ptr(dev);
+ unsigned int *clkmuxallocs[64], *muxallocs[64];
+ const char *p[10];
+ unsigned int cm[10], m[10], *tmpclkmux, *tmpmux;
+ struct clk clk, *c;
+ int ret, muxallocindex = 0, clkmuxallocindex = 0, i, j;
+ static const struct clk_range r = { 0, 0 };
+
+ if (!base)
+ return -EINVAL;
+
+ memset(muxallocs, 0, ARRAY_SIZE(muxallocs));
+ memset(clkmuxallocs, 0, ARRAY_SIZE(clkmuxallocs));
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return ret;
+
+ ret = clk_get_by_id(clk.id, &c);
+ if (ret)
+ return ret;
+
+ clk_names[ID_TD_SLCK] = kmemdup(clk_hw_get_name(c),
+ strlen(clk_hw_get_name(c)) + 1,
+ GFP_KERNEL);
+ if (!clk_names[ID_TD_SLCK])
+ return -ENOMEM;
+
+ ret = clk_get_by_index(dev, 1, &clk);
+ if (ret)
+ return ret;
+
+ ret = clk_get_by_id(clk.id, &c);
+ if (ret)
+ return ret;
+
+ clk_names[ID_MD_SLCK] = kmemdup(clk_hw_get_name(c),
+ strlen(clk_hw_get_name(c)) + 1,
+ GFP_KERNEL);
+ if (!clk_names[ID_MD_SLCK])
+ return -ENOMEM;
+
+ ret = clk_get_by_index(dev, 2, &clk);
+ if (ret)
+ return ret;
+
+ clk_names[ID_MAIN_XTAL] = kmemdup(clk_hw_get_name(&clk),
+ strlen(clk_hw_get_name(&clk)) + 1,
+ GFP_KERNEL);
+ if (!clk_names[ID_MAIN_XTAL])
+ return -ENOMEM;
+
+ /* Register main rc oscillator. */
+ c = at91_clk_main_rc(base, clk_names[ID_MAIN_RC_OSC],
+ NULL);
+ if (IS_ERR(c)) {
+ ret = PTR_ERR(c);
+ goto fail;
+ }
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_RC_OSC), c);
+
+ /* Register main oscillator. */
+ c = at91_clk_main_osc(base, clk_names[ID_MAIN_OSC],
+ clk_names[ID_MAIN_XTAL], false);
+ if (IS_ERR(c)) {
+ ret = PTR_ERR(c);
+ goto fail;
+ }
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_OSC), c);
+
+ /* Register mainck. */
+ p[0] = clk_names[ID_MAIN_RC_OSC];
+ p[1] = clk_names[ID_MAIN_OSC];
+ cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_RC_OSC);
+ cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_OSC);
+ prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm, 2,
+ fail);
+ c = at91_clk_sam9x5_main(base, clk_names[ID_MAINCK], p,
+ 2, tmpclkmux, PMC_TYPE_CORE);
+ if (IS_ERR(c)) {
+ ret = PTR_ERR(c);
+ goto fail;
+ }
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK), c);
+
+ /* Register PLL fracs clocks. */
+ for (i = 0; i < ARRAY_SIZE(sam9x7_plls); i++) {
+ if (sam9x7_plls[i].t != PLL_TYPE_FRAC)
+ continue;
+
+ c = sam9x60_clk_register_frac_pll(base, sam9x7_plls[i].n,
+ sam9x7_plls[i].p,
+ sam9x7_plls[i].id,
+ sam9x7_plls[i].c,
+ sam9x7_plls[i].l,
+ sam9x7_plls[i].f);
+ if (IS_ERR(c)) {
+ ret = PTR_ERR(c);
+ goto fail;
+ }
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, sam9x7_plls[i].cid), c);
+ }
+
+ /* Register PLL div clocks. */
+ for (i = 0; i < ARRAY_SIZE(sam9x7_plls); i++) {
+ if (sam9x7_plls[i].t != PLL_TYPE_DIV)
+ continue;
+
+ c = sam9x60_clk_register_div_pll(base, sam9x7_plls[i].n,
+ sam9x7_plls[i].p,
+ sam9x7_plls[i].id,
+ sam9x7_plls[i].c,
+ sam9x7_plls[i].l,
+ sam9x7_plls[i].f);
+ if (IS_ERR(c)) {
+ ret = PTR_ERR(c);
+ goto fail;
+ }
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, sam9x7_plls[i].cid), c);
+ }
+
+ /* Register MCK pres clock. */
+ p[0] = clk_names[ID_MD_SLCK];
+ p[1] = clk_names[ID_MAINCK];
+ p[2] = clk_names[ID_PLL_A_DIV];
+ p[3] = clk_names[ID_PLL_U_DIV];
+ cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MD_SLCK);
+ cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK);
+ cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_A_DIV);
+ cm[3] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_U_DIV);
+ prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm, 4,
+ fail);
+ c = at91_clk_register_master_pres(base, clk_names[ID_MCK_PRES], p, 4,
+ &mck_layout, &mck_characteristics,
+ tmpclkmux);
+ if (IS_ERR(c)) {
+ ret = PTR_ERR(c);
+ goto fail;
+ }
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK_PRES), c);
+
+ /* Register MCK div clock. */
+ c = at91_clk_register_master_div(base, clk_names[ID_MCK_DIV],
+ clk_names[ID_MCK_PRES],
+ &mck_layout, &mck_characteristics);
+ if (IS_ERR(c)) {
+ ret = PTR_ERR(c);
+ goto fail;
+ }
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK_DIV), c);
+
+ /* Register programmable clocks. */
+ p[0] = clk_names[ID_MD_SLCK];
+ p[1] = clk_names[ID_TD_SLCK];
+ p[2] = clk_names[ID_MAINCK];
+ p[3] = clk_names[ID_MCK_DIV];
+ p[4] = clk_names[ID_PLL_A_DIV];
+ p[5] = clk_names[ID_PLL_U_DIV];
+ p[6] = clk_names[ID_PLL_AUDIO_DIVPMC];
+ cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MD_SLCK);
+ cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_TD_SLCK);
+ cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK);
+ cm[3] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK_DIV);
+ cm[4] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_A_DIV);
+ cm[5] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_U_DIV);
+ cm[6] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_AUDIO_DIVPMC);
+ for (i = 0; i < ARRAY_SIZE(sam9x7_prog); i++) {
+ prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm,
+ 7, fail);
+
+ c = at91_clk_register_programmable(base, sam9x7_prog[i].n, p,
+ 7, i, &programmable_layout,
+ tmpclkmux,
+ sam9x7_prog_mux_table);
+ if (IS_ERR(c)) {
+ ret = PTR_ERR(c);
+ goto fail;
+ }
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, sam9x7_prog[i].cid), c);
+ }
+
+ /* System clocks. */
+ for (i = 0; i < ARRAY_SIZE(sam9x7_systemck); i++) {
+ c = at91_clk_register_system(base, sam9x7_systemck[i].n,
+ sam9x7_systemck[i].p,
+ sam9x7_systemck[i].id);
+ if (IS_ERR(c)) {
+ ret = PTR_ERR(c);
+ goto fail;
+ }
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SYSTEM, sam9x7_systemck[i].cid),
+ c);
+ }
+
+ /* Peripheral clocks. */
+ for (i = 0; i < ARRAY_SIZE(sam9x7_periphck); i++) {
+ c = at91_clk_register_sam9x5_peripheral(base, &sam9x7_pcr_layout,
+ sam9x7_periphck[i].n,
+ clk_names[ID_MCK_DIV],
+ sam9x7_periphck[i].id,
+ &r);
+ if (IS_ERR(c)) {
+ ret = PTR_ERR(c);
+ goto fail;
+ }
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_PERIPHERAL,
+ sam9x7_periphck[i].id), c);
+ }
+
+ /* Generic clocks. */
+ p[0] = clk_names[ID_MD_SLCK];
+ p[1] = clk_names[ID_TD_SLCK];
+ p[2] = clk_names[ID_MAINCK];
+ p[3] = clk_names[ID_MCK_DIV];
+ m[0] = 0;
+ m[1] = 1;
+ m[2] = 2;
+ m[3] = 3;
+ cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MD_SLCK);
+ cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_TD_SLCK);
+ cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK);
+ cm[3] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK_DIV);
+ for (i = 0; i < ARRAY_SIZE(sam9x7_gck); i++) {
+ for (j = 0; j < sam9x7_gck[i].ep_count; j++) {
+ p[4 + j] = sam9x7_gck[i].ep[j];
+ m[4 + j] = sam9x7_gck[i].ep_mux_table[j];
+ cm[4 + j] = AT91_TO_CLK_ID(PMC_TYPE_CORE,
+ sam9x7_gck[i].ep_clk_mux_table[j]);
+ }
+ prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm,
+ 4 + sam9x7_gck[i].ep_count, fail);
+ prepare_mux_table(muxallocs, muxallocindex, tmpmux, m,
+ 4 + sam9x7_gck[i].ep_count, fail);
+
+ c = at91_clk_register_generic(base, &sam9x7_pcr_layout,
+ sam9x7_gck[i].n, p, tmpclkmux,
+ tmpmux, 4 + sam9x7_gck[i].ep_count,
+ sam9x7_gck[i].id,
+ &sam9x7_gck[i].r);
+ if (IS_ERR(c)) {
+ ret = PTR_ERR(c);
+ goto fail;
+ }
+ clk_dm(AT91_TO_CLK_ID(PMC_TYPE_GCK, sam9x7_gck[i].id), c);
+ }
+
+ return 0;
+
+fail:
+ for (i = 0; i < ARRAY_SIZE(muxallocs); i++)
+ kfree(muxallocs[i]);
+
+ for (i = 0; i < ARRAY_SIZE(clkmuxallocs); i++)
+ kfree(clkmuxallocs[i]);
+
+ return ret;
+}
+
+static const struct udevice_id sam9x7_clk_ids[] = {
+ { .compatible = "microchip,sam9x7-pmc" },
+ { /* Sentinel. */ },
+};
+
+U_BOOT_DRIVER(at91_sam9x7_pmc) = {
+ .name = "at91-sam9x7-pmc",
+ .id = UCLASS_CLK,
+ .of_match = sam9x7_clk_ids,
+ .ops = &at91_clk_ops,
+ .probe = sam9x7_clk_probe,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c
index 63b2c647467..c0e27828b1a 100644
--- a/drivers/clk/at91/sama7g5.c
+++ b/drivers/clk/at91/sama7g5.c
@@ -158,11 +158,17 @@ static const struct clk_range pll_outputs[] = {
{ .min = 2343750, .max = 1200000000 },
};
+/* Fractional PLL core output range. */
+static const struct clk_range core_outputs[] = {
+ { .min = 600000000, .max = 1200000000 },
+};
+
/* PLL characteristics. */
static const struct clk_pll_characteristics pll_characteristics = {
.input = { .min = 12000000, .max = 50000000 },
.num_output = ARRAY_SIZE(pll_outputs),
.output = pll_outputs,
+ .core_output = core_outputs,
};
/* Layout for fractional PLLs. */
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 2167cd5ad0f..7262e89b512 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -34,6 +34,11 @@ struct clk *dev_get_clk_ptr(struct udevice *dev)
return (struct clk *)dev_get_uclass_priv(dev);
}
+ulong clk_get_id(const struct clk *clk)
+{
+ return (ulong)(clk->id & CLK_ID_MSK);
+}
+
#if CONFIG_IS_ENABLED(OF_PLATDATA)
int clk_get_by_phandle(struct udevice *dev, const struct phandle_1_arg *cells,
struct clk *clk)
@@ -43,7 +48,7 @@ int clk_get_by_phandle(struct udevice *dev, const struct phandle_1_arg *cells,
ret = device_get_by_ofplat_idx(cells->idx, &clk->dev);
if (ret)
return ret;
- clk->id = cells->arg[0];
+ clk->id = CLK_ID(dev, cells->arg[0]);
return 0;
}
@@ -61,7 +66,7 @@ static int clk_of_xlate_default(struct clk *clk,
}
if (args->args_count)
- clk->id = args->args[0];
+ clk->id = CLK_ID(clk->dev, args->args[0]);
else
clk->id = 0;
diff --git a/drivers/clk/clk_fixed_rate.c b/drivers/clk/clk_fixed_rate.c
index d1da05cc18a..95a77d2e041 100644
--- a/drivers/clk/clk_fixed_rate.c
+++ b/drivers/clk/clk_fixed_rate.c
@@ -44,6 +44,7 @@ void clk_fixed_rate_ofdata_to_plat_(struct udevice *dev,
dev_set_uclass_priv(dev, clk);
clk->dev = dev;
+ clk->id = CLK_ID(dev, 0);
clk->enable_count = 0;
}
diff --git a/drivers/clk/clk_sandbox.c b/drivers/clk/clk_sandbox.c
index 8dd77f18d90..c8c5a88c52d 100644
--- a/drivers/clk/clk_sandbox.c
+++ b/drivers/clk/clk_sandbox.c
@@ -13,24 +13,26 @@
static ulong sandbox_clk_get_rate(struct clk *clk)
{
struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
+ ulong id = clk_get_id(clk);
if (!priv->probed)
return -ENODEV;
- if (clk->id >= SANDBOX_CLK_ID_COUNT)
+ if (id >= SANDBOX_CLK_ID_COUNT)
return -EINVAL;
- return priv->rate[clk->id];
+ return priv->rate[id];
}
static ulong sandbox_clk_round_rate(struct clk *clk, ulong rate)
{
struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
+ ulong id = clk_get_id(clk);
if (!priv->probed)
return -ENODEV;
- if (clk->id >= SANDBOX_CLK_ID_COUNT)
+ if (id >= SANDBOX_CLK_ID_COUNT)
return -EINVAL;
if (!rate)
@@ -43,18 +45,19 @@ static ulong sandbox_clk_set_rate(struct clk *clk, ulong rate)
{
struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
ulong old_rate;
+ ulong id = clk_get_id(clk);
if (!priv->probed)
return -ENODEV;
- if (clk->id >= SANDBOX_CLK_ID_COUNT)
+ if (id >= SANDBOX_CLK_ID_COUNT)
return -EINVAL;
if (!rate)
return -EINVAL;
- old_rate = priv->rate[clk->id];
- priv->rate[clk->id] = rate;
+ old_rate = priv->rate[id];
+ priv->rate[id] = rate;
return old_rate;
}
@@ -62,14 +65,15 @@ static ulong sandbox_clk_set_rate(struct clk *clk, ulong rate)
static int sandbox_clk_enable(struct clk *clk)
{
struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
+ ulong id = clk_get_id(clk);
if (!priv->probed)
return -ENODEV;
- if (clk->id >= SANDBOX_CLK_ID_COUNT)
+ if (id >= SANDBOX_CLK_ID_COUNT)
return -EINVAL;
- priv->enabled[clk->id] = true;
+ priv->enabled[id] = true;
return 0;
}
@@ -77,14 +81,15 @@ static int sandbox_clk_enable(struct clk *clk)
static int sandbox_clk_disable(struct clk *clk)
{
struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
+ ulong id = clk_get_id(clk);
if (!priv->probed)
return -ENODEV;
- if (clk->id >= SANDBOX_CLK_ID_COUNT)
+ if (id >= SANDBOX_CLK_ID_COUNT)
return -EINVAL;
- priv->enabled[clk->id] = false;
+ priv->enabled[id] = false;
return 0;
}
@@ -92,11 +97,12 @@ static int sandbox_clk_disable(struct clk *clk)
static int sandbox_clk_request(struct clk *clk)
{
struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
+ ulong id = clk_get_id(clk);
- if (clk->id >= SANDBOX_CLK_ID_COUNT)
+ if (id >= SANDBOX_CLK_ID_COUNT)
return -EINVAL;
- priv->requested[clk->id] = true;
+ priv->requested[id] = true;
return 0;
}
diff --git a/drivers/clk/clk_sandbox_ccf.c b/drivers/clk/clk_sandbox_ccf.c
index f96a15c30b3..9b8036d41aa 100644
--- a/drivers/clk/clk_sandbox_ccf.c
+++ b/drivers/clk/clk_sandbox_ccf.c
@@ -235,47 +235,47 @@ static int sandbox_clk_ccf_probe(struct udevice *dev)
void *base = NULL;
u32 reg;
- clk_dm(SANDBOX_CLK_PLL3,
- sandbox_clk_pllv3(SANDBOX_PLLV3_USB, "pll3_usb_otg", "osc",
- base + 0x10, 0x3));
+ dev_clk_dm(dev, SANDBOX_CLK_PLL3,
+ sandbox_clk_pllv3(SANDBOX_PLLV3_USB, "pll3_usb_otg", "osc",
+ base + 0x10, 0x3));
- clk_dm(SANDBOX_CLK_PLL3_60M,
- sandbox_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8));
+ dev_clk_dm(dev, SANDBOX_CLK_PLL3_60M,
+ sandbox_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8));
- clk_dm(SANDBOX_CLK_PLL3_80M,
- sandbox_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6));
+ dev_clk_dm(dev, SANDBOX_CLK_PLL3_80M,
+ sandbox_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6));
/* The HW adds +1 to the divider value (2+1) is the divider */
reg = (2 << 19);
- clk_dm(SANDBOX_CLK_ECSPI_ROOT,
- sandbox_clk_divider("ecspi_root", "pll3_60m", &reg, 19, 6));
+ dev_clk_dm(dev, SANDBOX_CLK_ECSPI_ROOT,
+ sandbox_clk_divider("ecspi_root", "pll3_60m", &reg, 19, 6));
reg = 0;
- clk_dm(SANDBOX_CLK_ECSPI0,
- sandbox_clk_gate("ecspi0", "ecspi_root", &reg, 0, 0));
+ dev_clk_dm(dev, SANDBOX_CLK_ECSPI0,
+ sandbox_clk_gate("ecspi0", "ecspi_root", &reg, 0, 0));
- clk_dm(SANDBOX_CLK_ECSPI1,
- sandbox_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0));
+ dev_clk_dm(dev, SANDBOX_CLK_ECSPI1,
+ sandbox_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0));
/* Select 'pll3_60m' */
reg = 0;
- clk_dm(SANDBOX_CLK_USDHC1_SEL,
- sandbox_clk_mux("usdhc1_sel", &reg, 16, 1, usdhc_sels,
- ARRAY_SIZE(usdhc_sels)));
+ dev_clk_dm(dev, SANDBOX_CLK_USDHC1_SEL,
+ sandbox_clk_mux("usdhc1_sel", &reg, 16, 1, usdhc_sels,
+ ARRAY_SIZE(usdhc_sels)));
/* Select 'pll3_80m' */
reg = BIT(17);
- clk_dm(SANDBOX_CLK_USDHC2_SEL,
- sandbox_clk_mux("usdhc2_sel", &reg, 17, 1, usdhc_sels,
- ARRAY_SIZE(usdhc_sels)));
+ dev_clk_dm(dev, SANDBOX_CLK_USDHC2_SEL,
+ sandbox_clk_mux("usdhc2_sel", &reg, 17, 1, usdhc_sels,
+ ARRAY_SIZE(usdhc_sels)));
reg = BIT(28) | BIT(24) | BIT(16);
- clk_dm(SANDBOX_CLK_I2C,
- sandbox_clk_composite("i2c", i2c_sels, ARRAY_SIZE(i2c_sels),
- &reg, CLK_SET_RATE_UNGATE));
+ dev_clk_dm(dev, SANDBOX_CLK_I2C,
+ sandbox_clk_composite("i2c", i2c_sels, ARRAY_SIZE(i2c_sels),
+ &reg, CLK_SET_RATE_UNGATE));
- clk_dm(SANDBOX_CLK_I2C_ROOT,
- sandbox_clk_gate2("i2c_root", "i2c", base + 0x7c, 0));
+ dev_clk_dm(dev, SANDBOX_CLK_I2C_ROOT,
+ sandbox_clk_gate2("i2c_root", "i2c", base + 0x7c, 0));
return 0;
}
diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c
index af69850cdd8..cfb372e6190 100644
--- a/drivers/clk/clk_scmi.c
+++ b/drivers/clk/clk_scmi.c
@@ -84,26 +84,47 @@ static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks)
static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name,
u32 *attr)
{
+ struct scmi_clock_priv *priv = dev_get_priv(dev);
struct scmi_clk_attribute_in in = {
.clock_id = clkid,
};
- struct scmi_clk_attribute_out out;
- struct scmi_msg msg = {
- .protocol_id = SCMI_PROTOCOL_ID_CLOCK,
- .message_id = SCMI_CLOCK_ATTRIBUTES,
- .in_msg = (u8 *)&in,
- .in_msg_sz = sizeof(in),
- .out_msg = (u8 *)&out,
- .out_msg_sz = sizeof(out),
- };
int ret;
- ret = devm_scmi_process_msg(dev, &msg);
- if (ret)
- return ret;
-
- *name = strdup(out.clock_name);
- *attr = out.attributes;
+ if (priv->version >= 0x20000) {
+ struct scmi_clk_attribute_out_v2 out;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_CLOCK,
+ .message_id = SCMI_CLOCK_ATTRIBUTES,
+ .in_msg = (u8 *)&in,
+ .in_msg_sz = sizeof(in),
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+
+ *name = strdup(out.clock_name);
+ *attr = out.attributes;
+ } else {
+ struct scmi_clk_attribute_out out;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_CLOCK,
+ .message_id = SCMI_CLOCK_ATTRIBUTES,
+ .in_msg = (u8 *)&in,
+ .in_msg_sz = sizeof(in),
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret)
+ return ret;
+
+ *name = strdup(out.clock_name);
+ *attr = out.attributes;
+ }
return 0;
}
@@ -111,7 +132,7 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name,
static int scmi_clk_gate(struct clk *clk, int enable)
{
struct scmi_clk_state_in in = {
- .clock_id = clk->id,
+ .clock_id = clk_get_id(clk),
.attributes = enable,
};
struct scmi_clk_state_out out;
@@ -176,7 +197,7 @@ static int scmi_clk_disable(struct clk *clk)
static ulong scmi_clk_get_rate(struct clk *clk)
{
struct scmi_clk_rate_get_in in = {
- .clock_id = clk->id,
+ .clock_id = clk_get_id(clk),
};
struct scmi_clk_rate_get_out out;
struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
@@ -198,7 +219,7 @@ static ulong scmi_clk_get_rate(struct clk *clk)
static ulong __scmi_clk_set_rate(struct clk *clk, ulong rate)
{
struct scmi_clk_rate_set_in in = {
- .clock_id = clk->id,
+ .clock_id = clk_get_id(clk),
.flags = SCMI_CLK_RATE_ROUND_CLOSEST,
.rate_lsb = (u32)rate,
.rate_msb = (u32)((u64)rate >> 32),
@@ -257,6 +278,9 @@ static int scmi_clk_probe(struct udevice *dev)
if (!CONFIG_IS_ENABLED(CLK_CCF))
return 0;
+ ret = scmi_generic_protocol_version(dev, SCMI_PROTOCOL_ID_CLOCK,
+ &priv->version);
+
/* register CCF children: CLK UCLASS, no probed again */
if (device_get_uclass_id(dev->parent) == UCLASS_CLK)
return 0;
@@ -289,7 +313,7 @@ static int scmi_clk_probe(struct udevice *dev)
return ret;
}
- clk_dm(i, &clk_scmi->clk);
+ dev_clk_dm(dev, i, &clk_scmi->clk);
if (CLK_HAS_RESTRICTIONS(attributes)) {
u32 perm;
diff --git a/drivers/clk/clk_zynqmp.c b/drivers/clk/clk_zynqmp.c
index a8239e228cf..4f67c958d0f 100644
--- a/drivers/clk/clk_zynqmp.c
+++ b/drivers/clk/clk_zynqmp.c
@@ -108,6 +108,8 @@ static const resource_size_t zynqmp_crl_apb_clkc_base = 0xff5e0020;
#define PLLCTRL_POST_SRC_MASK (0x7 << PLLCTRL_POST_SRC_SHFT)
#define PLLCTRL_PRE_SRC_SHFT 20
#define PLLCTRL_PRE_SRC_MASK (0x7 << PLLCTRL_PRE_SRC_SHFT)
+#define PLL_TO_LPD_DIV_SHIFT 8
+#define PLL_TO_LPD_DIV_MASK (0x3f << PLL_TO_LPD_DIV_SHIFT)
#define NUM_MIO_PINS 77
@@ -334,6 +336,8 @@ static u32 zynqmp_clk_get_register(enum zynqmp_clk id)
return CRF_APB_TOPSW_LSBUS_CTRL;
case iopll_to_fpd:
return CRL_APB_IOPLL_TO_FPD_CTRL;
+ case dpll_to_lpd:
+ return CRF_APB_DPLL_TO_LPD_CTRL;
default:
debug("Invalid clk id%d\n", id);
}
@@ -397,6 +401,22 @@ static ulong zynqmp_clk_get_pll_rate(struct zynqmp_clk_priv *priv,
if (clk_ctrl & (1 << 16))
freq /= 2;
+ if (id == dpll) {
+ u32 dpll_lpd_reg, cross_div;
+
+ dpll_lpd_reg = zynqmp_clk_get_register(dpll_to_lpd);
+
+ ret = zynqmp_mmio_read(dpll_lpd_reg, &cross_div);
+ if (ret) {
+ printf("%s mio read fail\n", __func__);
+ return -EIO;
+ }
+
+ cross_div = (cross_div & PLL_TO_LPD_DIV_MASK) >>
+ PLL_TO_LPD_DIV_SHIFT;
+ freq /= cross_div;
+ }
+
return freq;
}
diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig
index d17a54fb9b3..74d5fe73f94 100644
--- a/drivers/clk/imx/Kconfig
+++ b/drivers/clk/imx/Kconfig
@@ -14,6 +14,14 @@ config CLK_IMX6Q
help
This enables DM/DTS support for clock driver in i.MX6Q platforms.
+config CLK_IMX6UL
+ bool "Clock support for i.MX6UL"
+ depends on ARCH_MX6
+ select CLK
+ select CLK_CCF
+ help
+ This enables DM/DTS support for clock driver in i.MX6UL platforms.
+
config CLK_IMX8
bool "Clock support for i.MX8"
depends on ARCH_IMX8
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index a89ee7acb12..b10221a195c 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -4,6 +4,7 @@
obj-$(CONFIG_$(PHASE_)CLK_CCF) += clk-gate2.o clk-pllv3.o clk-pfd.o
obj-$(CONFIG_$(PHASE_)CLK_IMX6Q) += clk-imx6q.o
+obj-$(CONFIG_$(PHASE_)CLK_IMX6UL) += clk-imx6ul.o
obj-$(CONFIG_CLK_IMX8) += clk-imx8.o
ifdef CONFIG_CLK_IMX8
diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c
index 81e19d393cf..b3926564a22 100644
--- a/drivers/clk/imx/clk-fracn-gppll.c
+++ b/drivers/clk/imx/clk-fracn-gppll.c
@@ -10,6 +10,7 @@
#include <dm/devres.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
+#include <linux/bug.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/err.h>
diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c
new file mode 100644
index 00000000000..32fb949ffbc
--- /dev/null
+++ b/drivers/clk/imx/clk-imx6ul.c
@@ -0,0 +1,289 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 Amarula Solutions Software Engineering
+ * Michael Trimarchi, Amarula Solutions Software Engineering, michael@amarulasolutions.com
+ */
+
+#include <clk-uclass.h>
+#include <dm.h>
+#include <log.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <dt-bindings/clock/imx6ul-clock.h>
+
+#include "clk.h"
+
+static int imx6ul_clk_request(struct clk *clk)
+{
+ debug("%s: request clk id %ld\n", __func__, clk->id);
+
+ if (clk->id < IMX6UL_CLK_DUMMY || clk->id >= IMX6UL_CLK_END) {
+ printf("%s: Invalid clk ID #%lu\n", __func__, clk->id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct clk_ops imx6ul_clk_ops = {
+ .request = imx6ul_clk_request,
+ .set_rate = ccf_clk_set_rate,
+ .get_rate = ccf_clk_get_rate,
+ .enable = ccf_clk_enable,
+ .disable = ccf_clk_disable,
+};
+
+static const char *const pll_bypass_src_sels[] = { "osc", "dummy", };
+static const char *const pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", };
+static const char *const bch_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
+static const char *const gpmi_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
+
+static const char *const enfc_sels[] = { "pll2_pfd0_352m", "pll2_bus", "pll3_usb_otg", "pll2_pfd2_396m",
+ "pll3_pfd3_454m", "dummy", "dummy", "dummy", };
+static const char *const usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
+static const char *const periph_sels[] = { "periph_pre", "periph_clk2", };
+static const char *const periph2_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m",
+ "pll4_audio_div", };
+static const char *const periph_clk2_sels[] = { "pll3_usb_otg", "osc", "pll2_bypass_src", };
+static const char *const periph2_clk2_sels[] = { "pll3_usb_otg", "osc", };
+static const char *const perclk_sels[] = { "ipg", "osc", };
+
+static const char *const periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m",
+ "pll2_198m", };
+static const char *const uart_sels[] = { "pll3_80m", "osc", };
+static const char *const ecspi_sels[] = { "pll3_60m", "osc", };
+
+static int imx6ul_clk_probe(struct udevice *dev)
+{
+ struct clk osc_clk;
+ void *base;
+ int ret;
+
+ /* Anatop clocks */
+ base = (void *)ANATOP_BASE_ADDR;
+
+ clk_dm(IMX6UL_CLK_DUMMY, clk_register_fixed_rate(NULL, "dummy", 0));
+
+ ret = clk_get_by_name(dev, "osc", &osc_clk);
+ if (ret)
+ return ret;
+
+ clk_dm(IMX6UL_CLK_OSC, dev_get_clk_ptr(osc_clk.dev));
+
+ clk_dm(IMX6UL_CLK_PLL2,
+ imx_clk_pllv3(dev, IMX_PLLV3_GENERIC, "pll2_bus", "osc",
+ base + 0x30, 0x1));
+ clk_dm(IMX6UL_CLK_PLL3,
+ imx_clk_pllv3(dev, IMX_PLLV3_USB, "pll3", "osc",
+ base + 0x10, 0x3));
+ clk_dm(IMX6UL_PLL3_BYPASS_SRC,
+ imx_clk_mux(dev, "pll3_bypass_src", base + 0x10, 14, 1,
+ pll_bypass_src_sels,
+ ARRAY_SIZE(pll_bypass_src_sels)));
+ clk_dm(IMX6UL_PLL3_BYPASS,
+ imx_clk_mux_flags(dev, "pll3_bypass", base + 0x10, 16, 1,
+ pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels),
+ CLK_SET_RATE_PARENT));
+ clk_dm(IMX6UL_CLK_PLL3_USB_OTG,
+ imx_clk_gate(dev, "pll3_usb_otg", "pll3_bypass", base + 0x10,
+ 13));
+ clk_dm(IMX6UL_CLK_PLL3_80M,
+ imx_clk_fixed_factor(dev, "pll3_80m", "pll3_usb_otg", 1, 6));
+ clk_dm(IMX6UL_CLK_PLL3_60M,
+ imx_clk_fixed_factor(dev, "pll3_60m", "pll3_usb_otg", 1, 8));
+ clk_dm(IMX6UL_CLK_PLL2_PFD0,
+ imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0));
+ clk_dm(IMX6UL_CLK_PLL2_PFD1,
+ imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1));
+ clk_dm(IMX6UL_CLK_PLL2_PFD2,
+ imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2));
+ clk_dm(IMX6UL_CLK_PLL2_PFD3,
+ imx_clk_pfd("pll2_pfd3_396m", "pll2_bus", base + 0x100, 3));
+ clk_dm(IMX6UL_CLK_PLL6,
+ imx_clk_pllv3(dev, IMX_PLLV3_ENET, "pll6", "osc", base + 0xe0,
+ 0x3));
+ clk_dm(IMX6UL_CLK_PLL6_ENET,
+ imx_clk_gate(dev, "pll6_enet", "pll6", base + 0xe0, 13));
+
+ /* CCM clocks */
+ base = dev_read_addr_ptr(dev);
+ if (!base)
+ return -EINVAL;
+
+ clk_dm(IMX6UL_CLK_GPMI_SEL,
+ imx_clk_mux(dev, "gpmi_sel", base + 0x1c, 19, 1, gpmi_sels,
+ ARRAY_SIZE(gpmi_sels)));
+ clk_dm(IMX6UL_CLK_BCH_SEL,
+ imx_clk_mux(dev, "bch_sel", base + 0x1c, 18, 1, bch_sels,
+ ARRAY_SIZE(bch_sels)));
+ clk_dm(IMX6UL_CLK_USDHC1_SEL,
+ imx_clk_mux(dev, "usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels,
+ ARRAY_SIZE(usdhc_sels)));
+ clk_dm(IMX6UL_CLK_USDHC2_SEL,
+ imx_clk_mux(dev, "usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels,
+ ARRAY_SIZE(usdhc_sels)));
+ clk_dm(IMX6UL_CLK_ECSPI_SEL,
+ imx_clk_mux(dev, "ecspi_sel", base + 0x38, 18, 1, ecspi_sels,
+ ARRAY_SIZE(ecspi_sels)));
+ clk_dm(IMX6UL_CLK_UART_SEL,
+ imx_clk_mux(dev, "uart_sel", base + 0x24, 6, 1, uart_sels,
+ ARRAY_SIZE(uart_sels)));
+ clk_dm(IMX6UL_CLK_ENFC_SEL,
+ imx_clk_mux(dev, "enfc_sel", base + 0x2c, 15, 3, enfc_sels,
+ ARRAY_SIZE(enfc_sels)));
+ clk_dm(IMX6UL_CLK_PERCLK_SEL,
+ imx_clk_mux(dev, "perclk_sel", base + 0x1c, 6, 1, perclk_sels,
+ ARRAY_SIZE(perclk_sels)));
+ clk_dm(IMX6UL_CLK_PERIPH_PRE,
+ imx_clk_mux(dev, "periph_pre", base + 0x18, 18, 2,
+ periph_pre_sels, ARRAY_SIZE(periph_pre_sels)));
+ clk_dm(IMX6UL_CLK_PERIPH2_PRE,
+ imx_clk_mux(dev, "periph2_pre", base + 0x18, 21, 2,
+ periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels)));
+ clk_dm(IMX6UL_CLK_PERIPH_CLK2_SEL,
+ imx_clk_mux(dev, "periph_clk2_sel", base + 0x18, 12, 2,
+ periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)));
+ clk_dm(IMX6UL_CLK_PERIPH2_CLK2_SEL,
+ imx_clk_mux(dev, "periph2_clk2_sel", base + 0x18, 20, 1,
+ periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels)));
+ clk_dm(IMX6UL_CLK_PERIPH,
+ imx_clk_busy_mux(dev, "periph", base + 0x14, 25, 1, base + 0x48,
+ 5, periph_sels, ARRAY_SIZE(periph_sels)));
+ clk_dm(IMX6UL_CLK_AHB,
+ imx_clk_busy_divider(dev, "ahb", "periph", base + 0x14, 10, 3,
+ base + 0x48, 1));
+ clk_dm(IMX6UL_CLK_PERIPH_CLK2,
+ imx_clk_divider(dev, "periph_clk2", "periph_clk2_sel",
+ base + 0x14, 27, 3));
+ clk_dm(IMX6UL_CLK_PERIPH2_CLK2,
+ imx_clk_divider(dev, "periph2_clk2", "periph2_clk2_sel",
+ base + 0x14, 0, 3));
+ clk_dm(IMX6UL_CLK_IPG,
+ imx_clk_divider(dev, "ipg", "ahb", base + 0x14, 8, 2));
+ clk_dm(IMX6UL_CLK_ENFC_PRED,
+ imx_clk_divider(dev, "enfc_pred", "enfc_sel", base + 0x2c, 18,
+ 3));
+ clk_dm(IMX6UL_CLK_ENFC_PODF,
+ imx_clk_divider(dev, "enfc_podf", "enfc_pred", base + 0x2c, 21,
+ 6));
+ clk_dm(IMX6UL_CLK_GPMI_PODF,
+ imx_clk_divider(dev, "gpmi_podf", "gpmi_sel", base + 0x24, 22,
+ 3));
+ clk_dm(IMX6UL_CLK_BCH_PODF,
+ imx_clk_divider(dev, "bch_podf", "bch_sel", base + 0x24, 19, 3));
+ clk_dm(IMX6UL_CLK_PERCLK,
+ imx_clk_divider(dev, "perclk", "perclk_sel", base + 0x1c, 0, 6));
+ clk_dm(IMX6UL_CLK_UART_PODF,
+ imx_clk_divider(dev, "uart_podf", "uart_sel", base + 0x24, 0,
+ 6));
+ clk_dm(IMX6UL_CLK_USDHC1_PODF,
+ imx_clk_divider(dev, "usdhc1_podf", "usdhc1_sel", base + 0x24,
+ 11, 3));
+ clk_dm(IMX6UL_CLK_USDHC2_PODF,
+ imx_clk_divider(dev, "usdhc2_podf", "usdhc2_sel", base + 0x24,
+ 16, 3));
+ clk_dm(IMX6UL_CLK_ECSPI_PODF,
+ imx_clk_divider(dev, "ecspi_podf", "ecspi_sel", base + 0x38, 19,
+ 6));
+
+ clk_dm(IMX6UL_CLK_APBHDMA,
+ imx_clk_gate2(dev, "apbh_dma", "bch_podf", base + 0x68, 4));
+ clk_dm(IMX6UL_CLK_ECSPI1,
+ imx_clk_gate2(dev, "ecspi1", "ecspi_podf", base + 0x6c, 0));
+ clk_dm(IMX6UL_CLK_ECSPI2,
+ imx_clk_gate2(dev, "ecspi2", "ecspi_podf", base + 0x6c, 2));
+ clk_dm(IMX6UL_CLK_ECSPI3,
+ imx_clk_gate2(dev, "ecspi3", "ecspi_podf", base + 0x6c, 4));
+ clk_dm(IMX6UL_CLK_ECSPI4,
+ imx_clk_gate2(dev, "ecspi4", "ecspi_podf", base + 0x6c, 6));
+
+ clk_dm(IMX6UL_CLK_USBOH3,
+ imx_clk_gate2(dev, "usboh3", "ipg", base + 0x80, 0));
+ clk_dm(IMX6UL_CLK_USDHC1,
+ imx_clk_gate2(dev, "usdhc1", "usdhc1_podf", base + 0x80, 2));
+ clk_dm(IMX6UL_CLK_USDHC2,
+ imx_clk_gate2(dev, "usdhc2", "usdhc2_podf", base + 0x80, 4));
+
+ clk_dm(IMX6UL_CLK_UART1_IPG,
+ imx_clk_gate2(dev, "uart1_ipg", "ipg", base + 0x7c, 24));
+ clk_dm(IMX6UL_CLK_UART1_SERIAL,
+ imx_clk_gate2(dev, "uart1_serial", "uart_podf", base + 0x7c, 24));
+ clk_dm(IMX6UL_CLK_UART2_IPG,
+ imx_clk_gate2(dev, "uart2_ipg", "ipg", base + 0x68, 28));
+ clk_dm(IMX6UL_CLK_UART2_SERIAL,
+ imx_clk_gate2(dev, "uart2_serial", "uart_podf", base + 0x68, 28));
+ clk_dm(IMX6UL_CLK_UART3_IPG,
+ imx_clk_gate2(dev, "uart3_ipg", "ipg", base + 0x6c, 10));
+ clk_dm(IMX6UL_CLK_UART3_SERIAL,
+ imx_clk_gate2(dev, "uart3_serial", "uart_podf", base + 0x6c, 10));
+ clk_dm(IMX6UL_CLK_UART4_IPG,
+ imx_clk_gate2(dev, "uart4_ipg", "ipg", base + 0x6c, 24));
+ clk_dm(IMX6UL_CLK_UART4_SERIAL,
+ imx_clk_gate2(dev, "uart4_serial", "uart_podf", base + 0x6c, 24));
+ clk_dm(IMX6UL_CLK_UART5_IPG,
+ imx_clk_gate2(dev, "uart5_ipg", "ipg", base + 0x74, 2));
+ clk_dm(IMX6UL_CLK_UART5_SERIAL,
+ imx_clk_gate2(dev, "uart5_serial", "uart_podf", base + 0x74, 2));
+ clk_dm(IMX6UL_CLK_UART6_IPG,
+ imx_clk_gate2(dev, "uart6_ipg", "ipg", base + 0x74, 6));
+ clk_dm(IMX6UL_CLK_UART6_SERIAL,
+ imx_clk_gate2(dev, "uart6_serial", "uart_podf", base + 0x74, 6));
+ clk_dm(IMX6UL_CLK_UART7_IPG,
+ imx_clk_gate2(dev, "uart7_ipg", "ipg", base + 0x7c, 26));
+ clk_dm(IMX6UL_CLK_UART7_SERIAL,
+ imx_clk_gate2(dev, "uart7_serial", "uart_podf", base + 0x7c, 26));
+ clk_dm(IMX6UL_CLK_UART8_IPG,
+ imx_clk_gate2(dev, "uart8_ipg", "ipg", base + 0x80, 14));
+ clk_dm(IMX6UL_CLK_UART8_SERIAL,
+ imx_clk_gate2(dev, "uart8_serial", "uart_podf", base + 0x80, 14));
+
+#if CONFIG_IS_ENABLED(NAND_MXS)
+ clk_dm(IMX6UL_CLK_PER_BCH,
+ imx_clk_gate2(dev, "per_bch", "bch_podf", base + 0x78, 12));
+ clk_dm(IMX6UL_CLK_GPMI_BCH_APB,
+ imx_clk_gate2(dev, "gpmi_bch_apb", "bch_podf", base + 0x78, 24));
+ clk_dm(IMX6UL_CLK_GPMI_BCH,
+ imx_clk_gate2(dev, "gpmi_bch", "gpmi_podf", base + 0x78, 26));
+ clk_dm(IMX6UL_CLK_GPMI_IO,
+ imx_clk_gate2(dev, "gpmi_io", "enfc_podf", base + 0x78, 28));
+ clk_dm(IMX6UL_CLK_GPMI_APB,
+ imx_clk_gate2(dev, "gpmi_apb", "bch_podf", base + 0x78, 30));
+#endif
+
+ clk_dm(IMX6UL_CLK_I2C1,
+ imx_clk_gate2(dev, "i2c1", "perclk", base + 0x70, 6));
+ clk_dm(IMX6UL_CLK_I2C2,
+ imx_clk_gate2(dev, "i2c2", "perclk", base + 0x70, 8));
+ clk_dm(IMX6UL_CLK_I2C3,
+ imx_clk_gate2(dev, "i2c3", "perclk", base + 0x70, 10));
+ clk_dm(IMX6UL_CLK_PWM1,
+ imx_clk_gate2(dev, "pwm1", "perclk", base + 0x78, 16));
+
+ clk_dm(IMX6UL_CLK_ENET,
+ imx_clk_gate2(dev, "enet", "ipg", base + 0x6c, 10));
+ clk_dm(IMX6UL_CLK_ENET_REF,
+ imx_clk_fixed_factor(dev, "enet_ref", "pll6_enet", 1, 1));
+
+ struct clk *clk, *clk1;
+
+ clk_get_by_id(IMX6UL_CLK_ENFC_SEL, &clk);
+ clk_get_by_id(IMX6UL_CLK_PLL2_PFD2, &clk1);
+
+ clk_set_parent(clk, clk1);
+
+ return 0;
+}
+
+static const struct udevice_id imx6ul_clk_ids[] = {
+ { .compatible = "fsl,imx6ul-ccm" },
+ { },
+};
+
+U_BOOT_DRIVER(imx6ul_clk) = {
+ .name = "clk_imx6ul",
+ .id = UCLASS_CLK,
+ .of_match = imx6ul_clk_ids,
+ .ops = &imx6ul_clk_ops,
+ .probe = imx6ul_clk_probe,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/clk/mediatek/clk-mt7981.c b/drivers/clk/mediatek/clk-mt7981.c
index 60814652322..6130c93d5e6 100644
--- a/drivers/clk/mediatek/clk-mt7981.c
+++ b/drivers/clk/mediatek/clk-mt7981.c
@@ -566,7 +566,7 @@ U_BOOT_DRIVER(mtk_clk_apmixedsys) = {
.of_match = mt7981_fixed_pll_compat,
.probe = mt7981_fixed_pll_probe,
.priv_auto = sizeof(struct mtk_clk_priv),
- .ops = &mtk_clk_topckgen_ops,
+ .ops = &mtk_clk_fixed_pll_ops,
.flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/clk/mediatek/clk-mt7986.c b/drivers/clk/mediatek/clk-mt7986.c
index f9d6f9c1749..cf298af644c 100644
--- a/drivers/clk/mediatek/clk-mt7986.c
+++ b/drivers/clk/mediatek/clk-mt7986.c
@@ -573,7 +573,7 @@ U_BOOT_DRIVER(mtk_clk_apmixedsys) = {
.of_match = mt7986_fixed_pll_compat,
.probe = mt7986_fixed_pll_probe,
.priv_auto = sizeof(struct mtk_clk_priv),
- .ops = &mtk_clk_topckgen_ops,
+ .ops = &mtk_clk_fixed_pll_ops,
.flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/clk/mediatek/clk-mt7987.c b/drivers/clk/mediatek/clk-mt7987.c
index 173686a38e8..b662d680b15 100644
--- a/drivers/clk/mediatek/clk-mt7987.c
+++ b/drivers/clk/mediatek/clk-mt7987.c
@@ -67,7 +67,7 @@ U_BOOT_DRIVER(mtk_clk_apmixedsys) = {
.of_match = mt7987_fixed_pll_compat,
.probe = mt7987_fixed_pll_probe,
.priv_auto = sizeof(struct mtk_clk_priv),
- .ops = &mtk_clk_topckgen_ops,
+ .ops = &mtk_clk_fixed_pll_ops,
.flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/clk/mediatek/clk-mt7988.c b/drivers/clk/mediatek/clk-mt7988.c
index 73fd9c6bea6..c6da42f970b 100644
--- a/drivers/clk/mediatek/clk-mt7988.c
+++ b/drivers/clk/mediatek/clk-mt7988.c
@@ -830,7 +830,7 @@ U_BOOT_DRIVER(mtk_clk_apmixedsys) = {
.of_match = mt7988_fixed_pll_compat,
.probe = mt7988_fixed_pll_probe,
.priv_auto = sizeof(struct mtk_clk_priv),
- .ops = &mtk_clk_topckgen_ops,
+ .ops = &mtk_clk_fixed_pll_ops,
.flags = DM_FLAG_PRE_RELOC,
};
diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c
index 66683aeb2d7..f91777e968a 100644
--- a/drivers/clk/mediatek/clk-mtk.c
+++ b/drivers/clk/mediatek/clk-mtk.c
@@ -47,6 +47,11 @@ static int mtk_clk_get_id(struct clk *clk)
return id;
}
+static int mtk_dummy_enable(struct clk *clk)
+{
+ return 0;
+}
+
static int mtk_gate_enable(void __iomem *base, const struct mtk_gate *gate)
{
u32 bit = BIT(gate->shift);
@@ -752,6 +757,12 @@ const struct clk_ops mtk_clk_apmixedsys_ops = {
.get_rate = mtk_apmixedsys_get_rate,
};
+const struct clk_ops mtk_clk_fixed_pll_ops = {
+ .enable = mtk_dummy_enable,
+ .disable = mtk_dummy_enable,
+ .get_rate = mtk_topckgen_get_rate,
+};
+
const struct clk_ops mtk_clk_topckgen_ops = {
.enable = mtk_clk_mux_enable,
.disable = mtk_clk_mux_disable,
diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
index c1d9901c10b..4ef1341aea6 100644
--- a/drivers/clk/mediatek/clk-mtk.h
+++ b/drivers/clk/mediatek/clk-mtk.h
@@ -283,6 +283,7 @@ struct mtk_cg_priv {
};
extern const struct clk_ops mtk_clk_apmixedsys_ops;
+extern const struct clk_ops mtk_clk_fixed_pll_ops;
extern const struct clk_ops mtk_clk_topckgen_ops;
extern const struct clk_ops mtk_clk_infrasys_ops;
extern const struct clk_ops mtk_clk_gate_ops;
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 3ea01f3c969..34e41461e72 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -31,6 +31,14 @@ config CLK_QCOM_IPQ4019
on the Snapdragon IPQ4019 SoC. This driver supports the clocks
and resets exposed by the GCC hardware block.
+config CLK_QCOM_IPQ5424
+ bool "Qualcomm IPQ5424 GCC"
+ select CLK_QCOM
+ help
+ Say Y here to enable support for the Global Clock Controller
+ on the Qualcomm IPQ5424 SoC. This driver supports the clocks
+ and resets exposed by the GCC hardware block.
+
config CLK_QCOM_IPQ9574
bool "Qualcomm IPQ9574 GCC"
select CLK_QCOM
@@ -55,6 +63,22 @@ config CLK_QCOM_QCS404
on the Snapdragon QCS404 SoC. This driver supports the clocks
and resets exposed by the GCC hardware block.
+config CLK_QCOM_QCS615
+ bool "Qualcomm QCS615 GCC"
+ select CLK_QCOM
+ help
+ Say Y here to enable support for the Global Clock Controller
+ on the Snapdragon QCS615 SoC. This driver supports the clocks
+ and resets exposed by the GCC hardware block.
+
+config CLK_QCOM_QCS8300
+ bool "Qualcomm QCS8300 GCC"
+ select CLK_QCOM
+ help
+ Say Y here to enable support for the Global Clock Controller
+ on the Snapdragon QCS8300 SoC. This driver supports the clocks
+ and resets exposed by the GCC hardware block.
+
config CLK_QCOM_SA8775P
bool "Qualcomm SA8775 GCC"
select CLK_QCOM
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index e13fc8c1071..b3d95b0faa3 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -7,9 +7,12 @@ obj-$(CONFIG_CLK_QCOM_SDM845) += clock-sdm845.o
obj-$(CONFIG_CLK_QCOM_APQ8016) += clock-apq8016.o
obj-$(CONFIG_CLK_QCOM_APQ8096) += clock-apq8096.o
obj-$(CONFIG_CLK_QCOM_IPQ4019) += clock-ipq4019.o
+obj-$(CONFIG_CLK_QCOM_IPQ5424) += clock-ipq5424.o
obj-$(CONFIG_CLK_QCOM_IPQ9574) += clock-ipq9574.o
obj-$(CONFIG_CLK_QCOM_QCM2290) += clock-qcm2290.o
obj-$(CONFIG_CLK_QCOM_QCS404) += clock-qcs404.o
+obj-$(CONFIG_CLK_QCOM_QCS8300) += clock-qcs8300.o
+obj-$(CONFIG_CLK_QCOM_QCS615) += clock-qcs615.o
obj-$(CONFIG_CLK_QCOM_SA8775P) += clock-sa8775p.o
obj-$(CONFIG_CLK_QCOM_SC7280) += clock-sc7280.o
obj-$(CONFIG_CLK_QCOM_SM6115) += clock-sm6115.o
diff --git a/drivers/clk/qcom/clock-ipq5424.c b/drivers/clk/qcom/clock-ipq5424.c
new file mode 100644
index 00000000000..40823a30ead
--- /dev/null
+++ b/drivers/clk/qcom/clock-ipq5424.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Clock drivers for Qualcomm ipq5424
+ *
+ * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <linux/bug.h>
+#include <linux/bitops.h>
+#include <dt-bindings/clock/qcom,ipq5424-gcc.h>
+#include <dt-bindings/reset/qcom,ipq5424-gcc.h>
+
+#include "clock-qcom.h"
+
+#define GCC_IM_SLEEP_CBCR 0x1834020u
+
+static ulong ipq5424_set_rate(struct clk *clk, ulong rate)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
+ switch (clk->id) {
+ case GCC_QUPV3_UART1_CLK:
+ clk_rcg_set_rate_mnd(priv->base, priv->data->clks[clk->id].reg,
+ 0, 144, 15625, CFG_CLK_SRC_GPLL0, 16);
+ return rate;
+ case GCC_SDCC1_APPS_CLK:
+ clk_rcg_set_rate_mnd(priv->base, priv->data->clks[clk->id].reg,
+ 5, 0, 0, CFG_CLK_SRC_GPLL2_MAIN, 16);
+ return rate;
+ }
+ return 0;
+}
+
+static const struct gate_clk ipq5424_clks[] = {
+ GATE_CLK(GCC_QUPV3_UART1_CLK, 0x302c, BIT(0)),
+ GATE_CLK(GCC_SDCC1_AHB_CLK, 0x3303c, BIT(0)),
+ GATE_CLK(GCC_SDCC1_APPS_CLK, 0x33004, BIT(1)),
+ GATE_CLK(GCC_IM_SLEEP_CLK, 0x34020, BIT(0)),
+};
+
+static int ipq5424_enable(struct clk *clk)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
+ if (clk->id >= ARRAY_SIZE(ipq5424_clks) || !ipq5424_clks[clk->id].reg)
+ return -EINVAL;
+
+ qcom_gate_clk_en(priv, clk->id);
+
+ return 0;
+}
+
+static const struct qcom_reset_map ipq5424_gcc_resets[] = {
+ [GCC_SDCC_BCR] = { 0x33000 },
+};
+
+static struct msm_clk_data ipq5424_gcc_data = {
+ .resets = ipq5424_gcc_resets,
+ .num_resets = ARRAY_SIZE(ipq5424_gcc_resets),
+ .clks = ipq5424_clks,
+ .num_clks = ARRAY_SIZE(ipq5424_clks),
+
+ .enable = ipq5424_enable,
+ .set_rate = ipq5424_set_rate,
+};
+
+static const struct udevice_id gcc_ipq5424_of_match[] = {
+ {
+ .compatible = "qcom,ipq5424-gcc",
+ .data = (ulong)&ipq5424_gcc_data,
+ },
+ { }
+};
+
+static int ipq5424_clk_probe(struct udevice *dev)
+{
+ /* Enable the sleep clock needed for the MMC block reset */
+ writel(BIT(0), GCC_IM_SLEEP_CBCR);
+
+ return 0;
+}
+
+U_BOOT_DRIVER(gcc_ipq5424) = {
+ .name = "gcc_ipq5424",
+ .id = UCLASS_NOP,
+ .of_match = gcc_ipq5424_of_match,
+ .probe = ipq5424_clk_probe,
+ .bind = qcom_cc_bind,
+ .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF,
+};
diff --git a/drivers/clk/qcom/clock-qcom.h b/drivers/clk/qcom/clock-qcom.h
index 1b60882dae4..3a4550d8536 100644
--- a/drivers/clk/qcom/clock-qcom.h
+++ b/drivers/clk/qcom/clock-qcom.h
@@ -13,6 +13,7 @@
#define CFG_CLK_SRC_GPLL0 (1 << 8)
#define CFG_CLK_SRC_GPLL0_AUX2 (2 << 8)
#define CFG_CLK_SRC_GPLL2 (2 << 8)
+#define CFG_CLK_SRC_GPLL2_MAIN (2 << 8)
#define CFG_CLK_SRC_GPLL9 (2 << 8)
#define CFG_CLK_SRC_GPLL0_ODD (3 << 8)
#define CFG_CLK_SRC_GPLL6 (4 << 8)
diff --git a/drivers/clk/qcom/clock-qcs615.c b/drivers/clk/qcom/clock-qcs615.c
new file mode 100644
index 00000000000..4700baba8c9
--- /dev/null
+++ b/drivers/clk/qcom/clock-qcs615.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Clock drivers for Qualcomm qcs615
+ *
+ * (C) Copyright 2024 Linaro Ltd.
+ */
+
+#include <linux/types.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <linux/bug.h>
+#include <linux/bitops.h>
+#include <dt-bindings/clock/qcom,qcs615-gcc.h>
+#include "clock-qcom.h"
+
+#define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf034
+#define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf01c
+#define USB3_PRIM_PHY_AUX_CMD_RCGR 0xf060
+
+#define GCC_QUPV3_WRAP0_S0_CLK_ENA_BIT BIT(10)
+#define GCC_QUPV3_WRAP0_S1_CLK_ENA_BIT BIT(11)
+#define GCC_QUPV3_WRAP0_S2_CLK_ENA_BIT BIT(12)
+#define GCC_QUPV3_WRAP0_S3_CLK_ENA_BIT BIT(13)
+#define GCC_QUPV3_WRAP0_S4_CLK_ENA_BIT BIT(14)
+#define GCC_QUPV3_WRAP0_S5_CLK_ENA_BIT BIT(15)
+
+#define GCC_QUPV3_WRAP1_S0_CLK_ENA_BIT BIT(22)
+#define GCC_QUPV3_WRAP1_S1_CLK_ENA_BIT BIT(23)
+#define GCC_QUPV3_WRAP1_S2_CLK_ENA_BIT BIT(24)
+#define GCC_QUPV3_WRAP1_S3_CLK_ENA_BIT BIT(25)
+#define GCC_QUPV3_WRAP1_S4_CLK_ENA_BIT BIT(26)
+#define GCC_QUPV3_WRAP1_S5_CLK_ENA_BIT BIT(27)
+
+static ulong qcs615_set_rate(struct clk *clk, ulong rate)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
+ if (clk->id < priv->data->num_clks)
+ debug("%s: %s, requested rate=%ld\n", __func__,
+ priv->data->clks[clk->id].name, rate);
+
+ switch (clk->id) {
+ case GCC_USB30_PRIM_MOCK_UTMI_CLK:
+ WARN(rate != 19200000, "Unexpected rate for USB30_PRIM_MOCK_UTMI_CLK: %lu\n", rate);
+ clk_rcg_set_rate(priv->base, USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR, 0, CFG_CLK_SRC_CXO);
+ return rate;
+ case GCC_USB30_PRIM_MASTER_CLK:
+ WARN(rate != 200000000, "Unexpected rate for USB30_PRIM_MASTER_CLK: %lu\n", rate);
+ clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR,
+ 5, 0, 0, CFG_CLK_SRC_GPLL0, 8);
+ clk_rcg_set_rate(priv->base, USB3_PRIM_PHY_AUX_CMD_RCGR, 0, 0);
+ return rate;
+ default:
+ return 0;
+ }
+}
+
+static const struct gate_clk qcs615_clks[] = {
+ GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0xf078, BIT(0)),
+ GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0xf010, BIT(0)),
+ GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0xf07c, BIT(0)),
+ GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0xf014, BIT(0)),
+ GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0xf018, BIT(0)),
+ GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0xf050, BIT(0)),
+ GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0xf054, BIT(0)),
+ GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0xf058, BIT(0)),
+ GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x5200c, GCC_QUPV3_WRAP0_S0_CLK_ENA_BIT),
+ GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x5200c, GCC_QUPV3_WRAP0_S1_CLK_ENA_BIT),
+ GATE_CLK(GCC_QUPV3_WRAP0_S2_CLK, 0x5200c, GCC_QUPV3_WRAP0_S2_CLK_ENA_BIT),
+ GATE_CLK(GCC_QUPV3_WRAP0_S3_CLK, 0x5200c, GCC_QUPV3_WRAP0_S3_CLK_ENA_BIT),
+ GATE_CLK(GCC_QUPV3_WRAP0_S4_CLK, 0x5200c, GCC_QUPV3_WRAP0_S4_CLK_ENA_BIT),
+ GATE_CLK(GCC_QUPV3_WRAP0_S5_CLK, 0x5200c, GCC_QUPV3_WRAP0_S5_CLK_ENA_BIT),
+ GATE_CLK(GCC_QUPV3_WRAP1_S0_CLK, 0x5200c, GCC_QUPV3_WRAP1_S0_CLK_ENA_BIT),
+ GATE_CLK(GCC_QUPV3_WRAP1_S1_CLK, 0x5200c, GCC_QUPV3_WRAP1_S1_CLK_ENA_BIT),
+ GATE_CLK(GCC_QUPV3_WRAP1_S2_CLK, 0x5200c, GCC_QUPV3_WRAP1_S2_CLK_ENA_BIT),
+ GATE_CLK(GCC_QUPV3_WRAP1_S3_CLK, 0x5200c, GCC_QUPV3_WRAP1_S3_CLK_ENA_BIT),
+ GATE_CLK(GCC_QUPV3_WRAP1_S4_CLK, 0x5200c, GCC_QUPV3_WRAP1_S4_CLK_ENA_BIT),
+ GATE_CLK(GCC_QUPV3_WRAP1_S5_CLK, 0x5200c, GCC_QUPV3_WRAP1_S5_CLK_ENA_BIT),
+ GATE_CLK(GCC_DISP_HF_AXI_CLK, 0xb038, BIT(0)),
+ GATE_CLK(GCC_DISP_AHB_CLK, 0xb032, BIT(0))
+};
+
+static int qcs615_enable(struct clk *clk)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
+ if (priv->data->num_clks < clk->id) {
+ debug("%s: unknown clk id %lu\n", __func__, clk->id);
+ return 0;
+ }
+
+ debug("%s: clk %ld: %s\n", __func__, clk->id, qcs615_clks[clk->id].name);
+
+ switch (clk->id) {
+ case GCC_AGGRE_USB3_PRIM_AXI_CLK:
+ qcom_gate_clk_en(priv, GCC_USB30_PRIM_MASTER_CLK);
+ fallthrough;
+ case GCC_USB30_PRIM_MASTER_CLK:
+ qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_AUX_CLK);
+ qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_COM_AUX_CLK);
+ break;
+ }
+
+ qcom_gate_clk_en(priv, clk->id);
+
+ return 0;
+}
+
+static const struct qcom_reset_map qcs615_gcc_resets[] = {
+ [GCC_EMAC_BCR] = { 0x6000 },
+ [GCC_QUSB2PHY_PRIM_BCR] = { 0xd000 },
+ [GCC_QUSB2PHY_SEC_BCR] = { 0xd004 },
+ [GCC_USB30_PRIM_BCR] = { 0xf000 },
+ [GCC_USB2_PHY_SEC_BCR] = { 0x50018 },
+ [GCC_USB3_DP_PHY_SEC_BCR] = { 0x50020 },
+ [GCC_USB3PHY_PHY_SEC_BCR] = { 0x5001c },
+ [GCC_PCIE_0_BCR] = { 0x6b000 },
+ [GCC_PCIE_0_PHY_BCR] = { 0x6c01c },
+ [GCC_PCIE_PHY_BCR] = { 0x6f000 },
+ [GCC_PCIE_PHY_COM_BCR] = { 0x6f010 },
+ [GCC_UFS_PHY_BCR] = { 0x77000 },
+ [GCC_USB20_SEC_BCR] = { 0xa6000 },
+ [GCC_USB3PHY_PHY_PRIM_SP0_BCR] = { 0x50008 },
+ [GCC_USB3_PHY_PRIM_SP0_BCR] = { 0x50000 },
+ [GCC_SDCC1_BCR] = { 0x12000 },
+ [GCC_SDCC2_BCR] = { 0x14000 }
+};
+
+static const struct qcom_power_map qcs615_gdscs[] = {
+ [UFS_PHY_GDSC] = { 0x77004 },
+ [USB30_PRIM_GDSC] = { 0xf004 },
+};
+
+static struct msm_clk_data sa8775_gcc_data = {
+ .resets = qcs615_gcc_resets,
+ .num_resets = ARRAY_SIZE(qcs615_gcc_resets),
+ .clks = qcs615_clks,
+ .num_clks = ARRAY_SIZE(qcs615_clks),
+
+ .power_domains = qcs615_gdscs,
+ .num_power_domains = ARRAY_SIZE(qcs615_gdscs),
+
+ .enable = qcs615_enable,
+ .set_rate = qcs615_set_rate,
+};
+
+static const struct udevice_id gcc_qcs615_of_match[] = {
+ {
+ .compatible = "qcom,qcs615-gcc",
+ .data = (ulong)&sa8775_gcc_data,
+ },
+ { }
+};
+
+U_BOOT_DRIVER(gcc_qcs615) = {
+ .name = "gcc_qcs615",
+ .id = UCLASS_NOP,
+ .of_match = gcc_qcs615_of_match,
+ .bind = qcom_cc_bind,
+ .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF,
+};
diff --git a/drivers/clk/qcom/clock-qcs8300.c b/drivers/clk/qcom/clock-qcs8300.c
new file mode 100644
index 00000000000..cd8aecdf788
--- /dev/null
+++ b/drivers/clk/qcom/clock-qcs8300.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2024-2025, Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ */
+
+#include <linux/types.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <linux/bug.h>
+#include <linux/bitops.h>
+#include <dt-bindings/clock/qcom,qcs8300-gcc.h>
+#include "clock-qcom.h"
+
+#define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf038
+#define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf020
+
+static ulong qcs8300_set_rate(struct clk *clk, ulong rate)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
+ if (clk->id < priv->data->num_clks)
+ debug("%s: %s, requested rate=%ld\n",
+ __func__, priv->data->clks[clk->id].name, rate);
+
+ switch (clk->id) {
+ case GCC_USB30_PRIM_MOCK_UTMI_CLK:
+ WARN(rate != 19200000, "Unexpected rate for USB30_PRIM_MOCK_UTMI_CLK: %lu\n", rate);
+ clk_rcg_set_rate(priv->base, USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR, 0, CFG_CLK_SRC_CXO);
+ return rate;
+ case GCC_USB30_PRIM_MASTER_CLK:
+ WARN(rate != 200000000, "Unexpected rate for USB30_PRIM_MASTER_CLK: %lu\n", rate);
+ clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR,
+ 1, 0, 0, CFG_CLK_SRC_GPLL0_ODD, 8);
+ clk_rcg_set_rate(priv->base, 0xf064, 0, 0);
+ return rate;
+ default:
+ return 0;
+ }
+}
+
+static const struct gate_clk qcs8300_clks[] = {
+ GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x1b088, BIT(0)),
+ GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0x1b018, BIT(0)),
+ GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x1b084, BIT(0)),
+ GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0x1b020, BIT(0)),
+ GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0x1b024, BIT(0)),
+ GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0x1b05c, BIT(0)),
+ GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0x1b060, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x83020, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x83018, BIT(0)),
+ GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x830d4, BIT(0)),
+ GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x83064, BIT(0)),
+};
+
+static int qcs8300_enable(struct clk *clk)
+{
+ struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
+ if (priv->data->num_clks < clk->id) {
+ debug("%s: unknown clk id %lu\n", __func__, clk->id);
+ return 0;
+ }
+
+ debug("%s: clk %ld: %s\n", __func__, clk->id, qcs8300_clks[clk->id].name);
+
+ switch (clk->id) {
+ case GCC_AGGRE_USB3_PRIM_AXI_CLK:
+ qcom_gate_clk_en(priv, GCC_USB30_PRIM_MASTER_CLK);
+ fallthrough;
+ case GCC_USB30_PRIM_MASTER_CLK:
+ qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_AUX_CLK);
+ qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_COM_AUX_CLK);
+ break;
+ }
+
+ qcom_gate_clk_en(priv, clk->id);
+
+ return 0;
+}
+
+static const struct qcom_reset_map qcs8300_gcc_resets[] = {
+ [GCC_EMAC0_BCR] = { 0xb6000 },
+ [GCC_PCIE_0_BCR] = { 0xa9000 },
+ [GCC_PCIE_0_LINK_DOWN_BCR] = { 0xbf000 },
+ [GCC_PCIE_0_NOCSR_COM_PHY_BCR] = { 0xbf008 },
+ [GCC_PCIE_0_PHY_BCR] = { 0xa9144 },
+ [GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR] = { 0xbf00c },
+ [GCC_PCIE_1_BCR] = { 0x77000 },
+ [GCC_PCIE_1_LINK_DOWN_BCR] = { 0xae084 },
+ [GCC_PCIE_1_NOCSR_COM_PHY_BCR] = { 0xae090 },
+ [GCC_PCIE_1_PHY_BCR] = { 0xae08c },
+ [GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR] = { 0xae094 },
+ [GCC_SDCC1_BCR] = { 0x20000 },
+ [GCC_UFS_PHY_BCR] = { 0x83000 },
+ [GCC_USB20_PRIM_BCR] = { 0x1c000 },
+ [GCC_USB2_PHY_PRIM_BCR] = { 0x5c01c },
+ [GCC_USB2_PHY_SEC_BCR] = { 0x5c020 },
+ [GCC_USB30_PRIM_BCR] = { 0x1b000 },
+ [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x5c008 },
+ [GCC_USB3_PHY_PRIM_BCR] = { 0x5c000 },
+ [GCC_USB3_PHY_TERT_BCR] = { 0x5c024 },
+ [GCC_USB3_UNIPHY_MP0_BCR] = { 0x5c00c },
+ [GCC_USB3_UNIPHY_MP1_BCR] = { 0x5c010 },
+ [GCC_USB3PHY_PHY_PRIM_BCR] = { 0x5c004 },
+ [GCC_USB3UNIPHY_PHY_MP0_BCR] = { 0x5c014 },
+ [GCC_USB3UNIPHY_PHY_MP1_BCR] = { 0x5c018 },
+ [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x76000 },
+ [GCC_VIDEO_BCR] = { 0x34000 },
+};
+
+static const struct qcom_power_map qcs8300_gdscs[] = {
+ [GCC_UFS_PHY_GDSC] = { 0x83004 },
+ [GCC_USB30_PRIM_GDSC] = { 0x1B004 },
+};
+
+static struct msm_clk_data qcs8300_gcc_data = {
+ .resets = qcs8300_gcc_resets,
+ .num_resets = ARRAY_SIZE(qcs8300_gcc_resets),
+ .clks = qcs8300_clks,
+ .num_clks = ARRAY_SIZE(qcs8300_clks),
+
+ .power_domains = qcs8300_gdscs,
+ .num_power_domains = ARRAY_SIZE(qcs8300_gdscs),
+
+ .enable = qcs8300_enable,
+ .set_rate = qcs8300_set_rate,
+};
+
+static const struct udevice_id gcc_qcs8300_of_match[] = {
+ {
+ .compatible = "qcom,qcs8300-gcc",
+ .data = (ulong)&qcs8300_gcc_data,
+ },
+ { }
+};
+
+U_BOOT_DRIVER(gcc_qcs8300) = {
+ .name = "gcc_qcs8300",
+ .id = UCLASS_NOP,
+ .of_match = gcc_qcs8300_of_match,
+ .bind = qcom_cc_bind,
+ .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF,
+};
diff --git a/drivers/clk/qcom/clock-sc7280.c b/drivers/clk/qcom/clock-sc7280.c
index 9aff8a847ad..47e0ca5f0e5 100644
--- a/drivers/clk/qcom/clock-sc7280.c
+++ b/drivers/clk/qcom/clock-sc7280.c
@@ -205,7 +205,7 @@ static const char *const sc7280_rcg_names[] = {
"GCC_PCIE_1_AUX_CLK_SRC",
};
-static struct msm_clk_data qcs404_gcc_data = {
+static struct msm_clk_data sc7280_gcc_data = {
.resets = sc7280_gcc_resets,
.num_resets = ARRAY_SIZE(sc7280_gcc_resets),
.clks = sc7280_clks,
@@ -225,7 +225,7 @@ static struct msm_clk_data qcs404_gcc_data = {
static const struct udevice_id gcc_sc7280_of_match[] = {
{
.compatible = "qcom,gcc-sc7280",
- .data = (ulong)&qcs404_gcc_data,
+ .data = (ulong)&sc7280_gcc_data,
},
{ }
};
diff --git a/drivers/clk/qcom/clock-sm8250.c b/drivers/clk/qcom/clock-sm8250.c
index 26396847d85..cc481258d22 100644
--- a/drivers/clk/qcom/clock-sm8250.c
+++ b/drivers/clk/qcom/clock-sm8250.c
@@ -360,7 +360,7 @@ static const char *const sm8250_rcg_names[] = {
"GCC_PCIE_2_AUX_CMD_RCGR",
};
-static struct msm_clk_data qcs404_gcc_data = {
+static struct msm_clk_data sm8250_gcc_data = {
.resets = sm8250_gcc_resets,
.num_resets = ARRAY_SIZE(sm8250_gcc_resets),
.clks = sm8250_clks,
@@ -381,7 +381,7 @@ static struct msm_clk_data qcs404_gcc_data = {
static const struct udevice_id gcc_sm8250_of_match[] = {
{
.compatible = "qcom,gcc-sm8250",
- .data = (ulong)&qcs404_gcc_data,
+ .data = (ulong)&sm8250_gcc_data,
},
{}
};
diff --git a/drivers/clk/qcom/clock-sm8650.c b/drivers/clk/qcom/clock-sm8650.c
index 364454644a6..7c49e99c005 100644
--- a/drivers/clk/qcom/clock-sm8650.c
+++ b/drivers/clk/qcom/clock-sm8650.c
@@ -193,6 +193,7 @@ static const struct gate_clk sm8650_clks[] = {
GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0x39060, BIT(0)),
GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0x39064, BIT(0)),
GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0x39068, BIT(0)),
+ GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x39088, BIT(0)),
};
static int sm8650_enable(struct clk *clk)
diff --git a/drivers/clk/renesas/clk-rcar-gen3.c b/drivers/clk/renesas/clk-rcar-gen3.c
index 375cc4a4930..5745acf4023 100644
--- a/drivers/clk/renesas/clk-rcar-gen3.c
+++ b/drivers/clk/renesas/clk-rcar-gen3.c
@@ -68,7 +68,7 @@ static int gen3_clk_get_parent(struct gen3_clk_priv *priv, struct clk *clk,
if (ret)
return ret;
- if (core->type == CLK_TYPE_GEN3_MDSEL) {
+ if (core->type == CLK_TYPE_GEN3_MDSEL || core->type == CLK_TYPE_GEN4_MDSEL) {
shift = priv->cpg_mode & BIT(core->offset) ? 0 : 16;
parent->dev = clk->dev;
parent->id = core->parent >> shift;
@@ -318,6 +318,8 @@ static u64 gen3_clk_get_rate64(struct clk *clk)
"FIXED");
case CLK_TYPE_GEN3_MDSEL:
+ fallthrough;
+ case CLK_TYPE_GEN4_MDSEL:
shift = priv->cpg_mode & BIT(core->offset) ? 0 : 16;
div = (core->div >> shift) & 0xffff;
rate = gen3_clk_get_rate64(&parent) / div;
diff --git a/drivers/clk/renesas/r8a774a1-cpg-mssr.c b/drivers/clk/renesas/r8a774a1-cpg-mssr.c
index d23041a8026..c8972106d90 100644
--- a/drivers/clk/renesas/r8a774a1-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a774a1-cpg-mssr.c
@@ -305,7 +305,7 @@ static const struct mstp_stop_table r8a774a1_mstp_table[] = {
{ 0xD00C7C1F, 0, 0xD00C7C1F, 0 },
{ 0x80000004, 0, 0x80000004, 0 },
{ 0x00DF0006, 0, 0x00DF0006, 0 },
- { 0XC5EACCCE, 0, 0XC5EACCCE, 0 },
+ { 0xC5EACCCE, 0, 0xC5EACCCE, 0 },
{ 0x29E1401C, 0, 0x29E1401C, 0 },
{ 0x00009FF1, 0, 0x00009FF1, 0 },
{ 0xFC4FDFE0, 0, 0xFC4FDFE0, 0 },
diff --git a/drivers/clk/stm32/Kconfig b/drivers/clk/stm32/Kconfig
index c05015efe8b..ea856be1662 100644
--- a/drivers/clk/stm32/Kconfig
+++ b/drivers/clk/stm32/Kconfig
@@ -36,3 +36,12 @@ config CLK_STM32MP13
help
Enable the STM32 clock (RCC) driver. Enable support for
manipulating STM32MP13's on-SoC clocks.
+
+config CLK_STM32MP25
+ bool "Enable RCC clock driver for STM32MP25"
+ depends on ARCH_STM32MP && CLK
+ default y if STM32MP25X
+ select CLK_STM32_CORE
+ help
+ Enable the STM32 clock (RCC) driver. Enable support for
+ manipulating STM32MP25's on-SoC clocks.
diff --git a/drivers/clk/stm32/Makefile b/drivers/clk/stm32/Makefile
index 20afbc3cfce..56adb8a4bbb 100644
--- a/drivers/clk/stm32/Makefile
+++ b/drivers/clk/stm32/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_CLK_STM32F) += clk-stm32f.o
obj-$(CONFIG_CLK_STM32H7) += clk-stm32h7.o
obj-$(CONFIG_CLK_STM32MP1) += clk-stm32mp1.o
obj-$(CONFIG_CLK_STM32MP13) += clk-stm32mp13.o
+obj-$(CONFIG_CLK_STM32MP25) += clk-stm32mp25.o
diff --git a/drivers/clk/stm32/clk-stm32-core.c b/drivers/clk/stm32/clk-stm32-core.c
index cad07cc952e..a0ae89d0912 100644
--- a/drivers/clk/stm32/clk-stm32-core.c
+++ b/drivers/clk/stm32/clk-stm32-core.c
@@ -41,12 +41,13 @@ int stm32_rcc_init(struct udevice *dev,
const struct clock_config *cfg = &data->tab_clocks[i];
struct clk *clk = ERR_PTR(-ENOENT);
- if (data->check_security && data->check_security(priv->base, cfg))
+ if (data->check_security && data->check_security(dev, priv->base, cfg))
continue;
if (cfg->setup) {
clk = cfg->setup(dev, cfg);
- clk->id = cfg->id;
+ /* set identifier of clock provider*/
+ dev_clk_dm(dev, cfg->id, clk);
} else {
dev_err(dev, "failed to register clock %s\n", cfg->name);
return -ENOENT;
@@ -69,11 +70,71 @@ ulong clk_stm32_get_rate_by_name(const char *name)
return 0;
}
+static const struct clk_ops *clk_dev_ops(struct udevice *dev)
+{
+ return (const struct clk_ops *)dev->driver->ops;
+}
+
+static int stm32_clk_endisable(struct clk *clk, bool enable)
+{
+ const struct clk_ops *ops;
+ struct clk *c = NULL;
+
+ if (!clk->id || clk_get_by_id(clk->id, &c))
+ return -ENOENT;
+
+ ops = clk_dev_ops(c->dev);
+ if (!ops->enable || !ops->disable)
+ return 0;
+
+ return enable ? ops->enable(c) : ops->disable(c);
+}
+
+static int stm32_clk_enable(struct clk *clk)
+{
+ return stm32_clk_endisable(clk, true);
+}
+
+static int stm32_clk_disable(struct clk *clk)
+{
+ return stm32_clk_endisable(clk, false);
+}
+
+static ulong stm32_clk_get_rate(struct clk *clk)
+{
+ const struct clk_ops *ops;
+ struct clk *c = NULL;
+
+ if (!clk->id || clk_get_by_id(clk->id, &c))
+ return -ENOENT;
+
+ ops = clk_dev_ops(c->dev);
+ if (!ops->get_rate)
+ return -ENOSYS;
+
+ return ops->get_rate(c);
+}
+
+static ulong stm32_clk_set_rate(struct clk *clk, unsigned long clk_rate)
+{
+ const struct clk_ops *ops;
+ struct clk *c = NULL;
+
+ if (!clk->id || clk_get_by_id(clk->id, &c))
+ return -ENOENT;
+
+ ops = clk_dev_ops(c->dev);
+ if (!ops->set_rate)
+ return -ENOSYS;
+
+ return ops->set_rate(c, clk_rate);
+}
+
const struct clk_ops stm32_clk_ops = {
- .enable = ccf_clk_enable,
- .disable = ccf_clk_disable,
- .get_rate = ccf_clk_get_rate,
- .set_rate = ccf_clk_set_rate,
+ .enable = stm32_clk_enable,
+ .disable = stm32_clk_disable,
+ .get_rate = stm32_clk_get_rate,
+ .set_rate = stm32_clk_set_rate,
};
#define RCC_MP_ENCLRR_OFFSET 4
diff --git a/drivers/clk/stm32/clk-stm32-core.h b/drivers/clk/stm32/clk-stm32-core.h
index f9ef0702005..baf2a996ef3 100644
--- a/drivers/clk/stm32/clk-stm32-core.h
+++ b/drivers/clk/stm32/clk-stm32-core.h
@@ -127,7 +127,7 @@ struct stm32_clock_match_data {
unsigned int num_clocks;
const struct clock_config *tab_clocks;
const struct clk_stm32_clock_data *clock_data;
- int (*check_security)(void __iomem *base,
+ int (*check_security)(struct udevice *dev, void __iomem *base,
const struct clock_config *cfg);
};
@@ -144,6 +144,7 @@ struct stm32mp_rcc_priv {
void __iomem *base;
u8 *gate_cpt;
const struct clk_stm32_clock_data *data;
+ struct clk osc_clk[6];
};
int stm32_rcc_init(struct udevice *dev,
diff --git a/drivers/clk/stm32/clk-stm32h7.c b/drivers/clk/stm32/clk-stm32h7.c
index 6acf2ff0a8f..aa3be414a29 100644
--- a/drivers/clk/stm32/clk-stm32h7.c
+++ b/drivers/clk/stm32/clk-stm32h7.c
@@ -114,6 +114,7 @@
#define QSPISRC_PER_CK 3
#define PWR_CR3 0x0c
+#define PWR_CR3_LDOEN BIT(1)
#define PWR_CR3_SCUEN BIT(2)
#define PWR_D3CR 0x18
#define PWR_D3CR_VOS_MASK GENMASK(15, 14)
@@ -375,7 +376,11 @@ int configure_clocks(struct udevice *dev)
clrsetbits_le32(pwr_base + PWR_D3CR, PWR_D3CR_VOS_MASK,
VOS_SCALE_1 << PWR_D3CR_VOS_SHIFT);
/* Lock supply configuration update */
+#if IS_ENABLED(CONFIG_TARGET_STM32H747_DISCO)
+ clrbits_le32(pwr_base + PWR_CR3, PWR_CR3_LDOEN);
+#else
clrbits_le32(pwr_base + PWR_CR3, PWR_CR3_SCUEN);
+#endif
while (!(readl(pwr_base + PWR_D3CR) & PWR_D3CR_VOSREADY))
;
diff --git a/drivers/clk/stm32/clk-stm32mp1.c b/drivers/clk/stm32/clk-stm32mp1.c
index 9cb69a01f7f..823ce132d0b 100644
--- a/drivers/clk/stm32/clk-stm32mp1.c
+++ b/drivers/clk/stm32/clk-stm32mp1.c
@@ -117,7 +117,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define RCC_DSICKSELR 0x924
#define RCC_ADCCKSELR 0x928
#define RCC_MP_APB1ENSETR 0xA00
-#define RCC_MP_APB2ENSETR 0XA08
+#define RCC_MP_APB2ENSETR 0xA08
#define RCC_MP_APB3ENSETR 0xA10
#define RCC_MP_AHB2ENSETR 0xA18
#define RCC_MP_AHB3ENSETR 0xA20
diff --git a/drivers/clk/stm32/clk-stm32mp13.c b/drivers/clk/stm32/clk-stm32mp13.c
index 362dba10252..b4d0890f902 100644
--- a/drivers/clk/stm32/clk-stm32mp13.c
+++ b/drivers/clk/stm32/clk-stm32mp13.c
@@ -3,7 +3,6 @@
* Copyright (C) 2022, STMicroelectronics - All Rights Reserved
* Author: Gabriel Fernandez <gabriel.fernandez@foss.st.com> for STMicroelectronics.
*/
-
#define LOG_CATEGORY UCLASS_CLK
#include <clk-uclass.h>
@@ -12,6 +11,22 @@
#include <asm/io.h>
#include <dt-bindings/clock/stm32mp13-clks.h>
#include <linux/clk-provider.h>
+#include <dt-bindings/clock/stm32mp13-clksrc.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/global_data.h>
+#include <clk-uclass.h>
+#include <div64.h>
+#include <dm/device_compat.h>
+#include <init.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <regmap.h>
+#include <spl.h>
+#include <syscon.h>
+#include <time.h>
+#include <vsprintf.h>
+#include <asm/arch/sys_proto.h>
#include "clk-stm32-core.h"
#include "stm32mp13_rcc.h"
@@ -130,46 +145,6 @@ static const char * const usbphy_src[] = {
"ck_hse", "pll4_r", "clk-hse-div2"
};
-enum enum_mux_cfg {
- MUX_I2C12,
- MUX_LPTIM45,
- MUX_SPI23,
- MUX_UART35,
- MUX_UART78,
- MUX_ADC1,
- MUX_ADC2,
- MUX_DCMIPP,
- MUX_ETH1,
- MUX_ETH2,
- MUX_FDCAN,
- MUX_FMC,
- MUX_I2C3,
- MUX_I2C4,
- MUX_I2C5,
- MUX_LPTIM1,
- MUX_LPTIM2,
- MUX_LPTIM3,
- MUX_QSPI,
- MUX_RNG1,
- MUX_SAES,
- MUX_SAI1,
- MUX_SAI2,
- MUX_SDMMC1,
- MUX_SDMMC2,
- MUX_SPDIF,
- MUX_SPI1,
- MUX_SPI4,
- MUX_SPI5,
- MUX_STGEN,
- MUX_UART1,
- MUX_UART2,
- MUX_UART4,
- MUX_UART6,
- MUX_USBO,
- MUX_USBPHY,
- MUX_MCO1,
- MUX_MCO2
-};
#define MUX_CFG(id, src, _offset, _shift, _witdh) \
[id] = { \
@@ -471,15 +446,6 @@ static const struct clk_div_table ck_trace_div_table[] = {
{ 0 },
};
-enum enum_div_cfg {
- DIV_MCO1,
- DIV_MCO2,
- DIV_TRACE,
- DIV_ETH1PTP,
- DIV_ETH2PTP,
- LAST_DIV
-};
-
#define DIV_CFG(id, _offset, _shift, _width, _flags, _table) \
[id] = { \
.reg_off = _offset, \
@@ -489,7 +455,7 @@ enum enum_div_cfg {
.table = _table, \
}
-static const struct stm32_div_cfg stm32mp13_dividers[LAST_DIV] = {
+static const struct stm32_div_cfg stm32mp13_dividers[] = {
DIV_CFG(DIV_MCO1, RCC_MCO1CFGR, 4, 4, 0, NULL),
DIV_CFG(DIV_MCO2, RCC_MCO2CFGR, 4, 4, 0, NULL),
DIV_CFG(DIV_TRACE, RCC_DBGCFGR, 0, 3, 0, ck_trace_div_table),
@@ -497,7 +463,7 @@ static const struct stm32_div_cfg stm32mp13_dividers[LAST_DIV] = {
DIV_CFG(DIV_ETH2PTP, RCC_ETH12CKSELR, 12, 4, 0, NULL),
};
-struct clk_stm32_securiy {
+struct clk_stm32_security {
u16 offset;
u8 bit_idx;
};
@@ -566,7 +532,8 @@ enum securit_clk {
.bit_idx = _bit_idx, \
}
-static const struct clk_stm32_securiy stm32mp13_security[] = {
+#ifdef CONFIG_TFABOOT
+static const struct clk_stm32_security stm32mp13_security[] = {
SECF(SECF_LPTIM2, RCC_APB3SECSR, RCC_APB3SECSR_LPTIM2SECF),
SECF(SECF_LPTIM3, RCC_APB3SECSR, RCC_APB3SECSR_LPTIM3SECF),
SECF(SECF_VREF, RCC_APB3SECSR, RCC_APB3SECSR_VREFSECF),
@@ -622,6 +589,7 @@ static const struct clk_stm32_securiy stm32mp13_security[] = {
SECF(SECF_MCO1, RCC_SECCFGR, RCC_SECCFGR_MCO1SECF),
SECF(SECF_MCO2, RCC_SECCFGR, RCC_SECCFGR_MCO2SECF),
};
+#endif
#define PCLK(_id, _name, _parent, _flags, _gate_id, _sec_id) \
STM32_GATE(_id, _name, _parent, _flags, _gate_id, _sec_id)
@@ -635,6 +603,7 @@ static const struct clk_stm32_securiy stm32mp13_security[] = {
_gate_id, _mux_id, NO_STM32_DIV)
static const struct clock_config stm32mp13_clock_cfg[] = {
+#ifndef CONFIG_XPL_BUILD
TIMER(TIM2_K, "tim2_k", "timg1_ck", 0, GATE_TIM2, SECF_NONE),
TIMER(TIM3_K, "tim3_k", "timg1_ck", 0, GATE_TIM3, SECF_NONE),
TIMER(TIM4_K, "tim4_k", "timg1_ck", 0, GATE_TIM4, SECF_NONE),
@@ -649,23 +618,28 @@ static const struct clock_config stm32mp13_clock_cfg[] = {
TIMER(TIM15_K, "tim15_k", "timg3_ck", 0, GATE_TIM15, SECF_TIM15),
TIMER(TIM16_K, "tim16_k", "timg3_ck", 0, GATE_TIM16, SECF_TIM16),
TIMER(TIM17_K, "tim17_k", "timg3_ck", 0, GATE_TIM17, SECF_TIM17),
+#endif
/* Peripheral clocks */
PCLK(SYSCFG, "syscfg", "pclk3", 0, GATE_SYSCFG, SECF_NONE),
PCLK(VREF, "vref", "pclk3", 0, GATE_VREF, SECF_VREF),
+#ifndef CONFIG_XPL_BUILD
PCLK(PMBCTRL, "pmbctrl", "pclk3", 0, GATE_PMBCTRL, SECF_NONE),
PCLK(HDP, "hdp", "pclk3", 0, GATE_HDP, SECF_NONE),
+#endif
PCLK(IWDG2, "iwdg2", "pclk4", 0, GATE_IWDG2APB, SECF_NONE),
PCLK(STGENRO, "stgenro", "pclk4", 0, GATE_STGENRO, SECF_STGENRO),
PCLK(TZPC, "tzpc", "pclk5", 0, GATE_TZC, SECF_TZC),
PCLK(IWDG1, "iwdg1", "pclk5", 0, GATE_IWDG1APB, SECF_IWDG1),
PCLK(BSEC, "bsec", "pclk5", 0, GATE_BSEC, SECF_BSEC),
+#ifndef CONFIG_XPL_BUILD
PCLK(DMA1, "dma1", "ck_mlahb", 0, GATE_DMA1, SECF_NONE),
PCLK(DMA2, "dma2", "ck_mlahb", 0, GATE_DMA2, SECF_NONE),
PCLK(DMAMUX1, "dmamux1", "ck_mlahb", 0, GATE_DMAMUX1, SECF_NONE),
PCLK(DMAMUX2, "dmamux2", "ck_mlahb", 0, GATE_DMAMUX2, SECF_DMAMUX2),
PCLK(ADC1, "adc1", "ck_mlahb", 0, GATE_ADC1, SECF_ADC1),
PCLK(ADC2, "adc2", "ck_mlahb", 0, GATE_ADC2, SECF_ADC2),
+#endif
PCLK(GPIOA, "gpioa", "pclk4", 0, GATE_GPIOA, SECF_NONE),
PCLK(GPIOB, "gpiob", "pclk4", 0, GATE_GPIOB, SECF_NONE),
PCLK(GPIOC, "gpioc", "pclk4", 0, GATE_GPIOC, SECF_NONE),
@@ -681,17 +655,23 @@ static const struct clock_config stm32mp13_clock_cfg[] = {
PCLK(HASH1, "hash1", "ck_axi", 0, GATE_HASH1, SECF_HASH1),
PCLK(BKPSRAM, "bkpsram", "ck_axi", 0, GATE_BKPSRAM, SECF_BKPSRAM),
PCLK(MDMA, "mdma", "ck_axi", 0, GATE_MDMA, SECF_NONE),
+#ifndef CONFIG_XPL_BUILD
PCLK(ETH1TX, "eth1tx", "ck_axi", 0, GATE_ETH1TX, SECF_ETH1TX),
PCLK(ETH1RX, "eth1rx", "ck_axi", 0, GATE_ETH1RX, SECF_ETH1RX),
PCLK(ETH1MAC, "eth1mac", "ck_axi", 0, GATE_ETH1MAC, SECF_ETH1MAC),
PCLK(ETH2TX, "eth2tx", "ck_axi", 0, GATE_ETH2TX, SECF_ETH2TX),
PCLK(ETH2RX, "eth2rx", "ck_axi", 0, GATE_ETH2RX, SECF_ETH2RX),
PCLK(ETH2MAC, "eth2mac", "ck_axi", 0, GATE_ETH2MAC, SECF_ETH2MAC),
+#endif
PCLK(CRC1, "crc1", "ck_axi", 0, GATE_CRC1, SECF_NONE),
+#ifndef CONFIG_XPL_BUILD
PCLK(USBH, "usbh", "ck_axi", 0, GATE_USBH, SECF_NONE),
+#endif
PCLK(DDRPERFM, "ddrperfm", "pclk4", 0, GATE_DDRPERFM, SECF_NONE),
+#ifndef CONFIG_XPL_BUILD
PCLK(ETH1STP, "eth1stp", "ck_axi", 0, GATE_ETH1STP, SECF_ETH1STP),
PCLK(ETH2STP, "eth2stp", "ck_axi", 0, GATE_ETH2STP, SECF_ETH2STP),
+#endif
/* Kernel clocks */
KCLK(SDMMC1_K, "sdmmc1_k", 0, GATE_SDMMC1, MUX_SDMMC1, SECF_SDMMC1),
@@ -702,8 +682,10 @@ static const struct clock_config stm32mp13_clock_cfg[] = {
KCLK(SPI3_K, "spi3_k", 0, GATE_SPI3, MUX_SPI23, SECF_NONE),
KCLK(I2C1_K, "i2c1_k", 0, GATE_I2C1, MUX_I2C12, SECF_NONE),
KCLK(I2C2_K, "i2c2_k", 0, GATE_I2C2, MUX_I2C12, SECF_NONE),
+#ifndef CONFIG_XPL_BUILD
KCLK(LPTIM4_K, "lptim4_k", 0, GATE_LPTIM4, MUX_LPTIM45, SECF_NONE),
KCLK(LPTIM5_K, "lptim5_k", 0, GATE_LPTIM5, MUX_LPTIM45, SECF_NONE),
+#endif
KCLK(USART3_K, "usart3_k", 0, GATE_USART3, MUX_UART35, SECF_NONE),
KCLK(UART5_K, "uart5_k", 0, GATE_UART5, MUX_UART35, SECF_NONE),
KCLK(UART7_K, "uart7_k", 0, GATE_UART7, MUX_UART78, SECF_NONE),
@@ -711,20 +693,29 @@ static const struct clock_config stm32mp13_clock_cfg[] = {
KCLK(RNG1_K, "rng1_k", 0, GATE_RNG1, MUX_RNG1, SECF_RNG1),
KCLK(USBPHY_K, "usbphy_k", 0, GATE_USBPHY, MUX_USBPHY, SECF_USBPHY),
KCLK(STGEN_K, "stgen_k", 0, GATE_STGENC, MUX_STGEN, SECF_STGENC),
+#ifndef CONFIG_XPL_BUILD
KCLK(SPDIF_K, "spdif_k", 0, GATE_SPDIF, MUX_SPDIF, SECF_NONE),
+#endif
KCLK(SPI1_K, "spi1_k", 0, GATE_SPI1, MUX_SPI1, SECF_NONE),
KCLK(SPI4_K, "spi4_k", 0, GATE_SPI4, MUX_SPI4, SECF_SPI4),
KCLK(SPI5_K, "spi5_k", 0, GATE_SPI5, MUX_SPI5, SECF_SPI5),
+#ifdef CONFIG_TFABOOT
KCLK(I2C3_K, "i2c3_k", 0, GATE_I2C3, MUX_I2C3, SECF_I2C3),
+#else
+ KCLK(I2C3_K, "i2c3_k", 0, GATE_I2C3, MUX_I2C3, SECF_NONE),
+#endif
KCLK(I2C4_K, "i2c4_k", 0, GATE_I2C4, MUX_I2C4, SECF_I2C4),
KCLK(I2C5_K, "i2c5_k", 0, GATE_I2C5, MUX_I2C5, SECF_I2C5),
+#ifndef CONFIG_XPL_BUILD
KCLK(LPTIM1_K, "lptim1_k", 0, GATE_LPTIM1, MUX_LPTIM1, SECF_NONE),
KCLK(LPTIM2_K, "lptim2_k", 0, GATE_LPTIM2, MUX_LPTIM2, SECF_LPTIM2),
KCLK(LPTIM3_K, "lptim3_k", 0, GATE_LPTIM3, MUX_LPTIM3, SECF_LPTIM3),
+#endif
KCLK(USART1_K, "usart1_k", 0, GATE_USART1, MUX_UART1, SECF_USART1),
KCLK(USART2_K, "usart2_k", 0, GATE_USART2, MUX_UART2, SECF_USART2),
KCLK(UART4_K, "uart4_k", 0, GATE_UART4, MUX_UART4, SECF_NONE),
KCLK(USART6_K, "uart6_k", 0, GATE_USART6, MUX_UART6, SECF_NONE),
+#ifndef CONFIG_XPL_BUILD
KCLK(FDCAN_K, "fdcan_k", 0, GATE_FDCAN, MUX_FDCAN, SECF_NONE),
KCLK(SAI1_K, "sai1_k", 0, GATE_SAI1, MUX_SAI1, SECF_NONE),
KCLK(SAI2_K, "sai2_k", 0, GATE_SAI2, MUX_SAI2, SECF_NONE),
@@ -732,7 +723,9 @@ static const struct clock_config stm32mp13_clock_cfg[] = {
KCLK(ADC2_K, "adc2_k", 0, GATE_ADC2, MUX_ADC2, SECF_ADC2),
KCLK(DCMIPP_K, "dcmipp_k", 0, GATE_DCMIPP, MUX_DCMIPP, SECF_DCMIPP),
KCLK(ADFSDM_K, "adfsdm_k", 0, GATE_ADFSDM, MUX_SAI1, SECF_NONE),
+#endif
KCLK(USBO_K, "usbo_k", 0, GATE_USBO, MUX_USBO, SECF_USBO),
+#ifndef CONFIG_XPL_BUILD
KCLK(ETH1CK_K, "eth1ck_k", 0, GATE_ETH1CK, MUX_ETH1, SECF_ETH1CK),
KCLK(ETH2CK_K, "eth2ck_k", 0, GATE_ETH2CK, MUX_ETH2, SECF_ETH2CK),
KCLK(SAES_K, "saes_k", 0, GATE_SAES, MUX_SAES, SECF_SAES),
@@ -742,6 +735,7 @@ static const struct clock_config stm32mp13_clock_cfg[] = {
GATE_LTDC, SECF_NONE),
STM32_GATE(DTS_K, "dts_k", "ck_lse", 0, GATE_DTS, SECF_NONE),
+#endif
STM32_COMPOSITE(ETH1PTP_K, "eth1ptp_k", CLK_OPS_PARENT_ENABLE |
CLK_SET_RATE_NO_REPARENT, SECF_ETH1CK,
@@ -767,16 +761,30 @@ static const struct clock_config stm32mp13_clock_cfg[] = {
STM32_COMPOSITE_NOMUX(CK_TRACE, "ck_trace", "ck_axi",
CLK_OPS_PARENT_ENABLE, SECF_NONE,
GATE_TRACECK, DIV_TRACE),
+
+#ifdef CONFIG_XPL_BUILD
+ STM32_GATE(AXIDCG, "axidcg", "ck_axi", CLK_IGNORE_UNUSED,
+ GATE_AXIDCG, SECF_NONE),
+ STM32_GATE(DDRC1, "ddrc1", "ck_axi", CLK_IGNORE_UNUSED,
+ GATE_DDRC1, SECF_NONE),
+ STM32_GATE(DDRPHYC, "ddrphyc", "pll2_r", CLK_IGNORE_UNUSED,
+ GATE_DDRPHYC, SECF_NONE),
+ STM32_GATE(DDRCAPB, "ddrcapb", "pclk4", CLK_IGNORE_UNUSED,
+ GATE_DDRCAPB, SECF_NONE),
+ STM32_GATE(DDRPHYCAPB, "ddrphycapb", "pclk4", CLK_IGNORE_UNUSED,
+ GATE_DDRPHYCAPB, SECF_NONE),
+#endif
};
-static int stm32mp13_check_security(void __iomem *base,
+#ifdef CONFIG_TFABOOT
+static int stm32mp13_check_security(struct udevice *dev, void __iomem *base,
const struct clock_config *cfg)
{
int sec_id = cfg->sec_id;
int secured = 0;
if (sec_id != SECF_NONE) {
- const struct clk_stm32_securiy *secf;
+ const struct clk_stm32_security *secf;
secf = &stm32mp13_security[sec_id];
secured = !!(readl(base + secf->offset) & BIT(secf->bit_idx));
@@ -784,6 +792,7 @@ static int stm32mp13_check_security(void __iomem *base,
return secured;
}
+#endif
static const struct stm32_clock_match_data stm32mp13_data = {
.tab_clocks = stm32mp13_clock_cfg,
@@ -794,16 +803,1204 @@ static const struct stm32_clock_match_data stm32mp13_data = {
.muxes = stm32mp13_muxes,
.dividers = stm32mp13_dividers,
},
+#ifdef CONFIG_TFABOOT
.check_security = stm32mp13_check_security,
+#endif
+};
+
+#ifndef CONFIG_TFABOOT
+
+enum stm32mp1_parent_id {
+/*
+ * _HSI, _HSE, _CSI, _LSI, _LSE should not be moved
+ * they are used as index in osc_clk[] as clock reference
+ */
+ _HSI,
+ _HSE,
+ _CSI,
+ _LSI,
+ _LSE,
+ _I2S_CKIN,
+ NB_OSC,
+
+/* other parent source */
+ _HSI_KER = NB_OSC,
+ _HSE_KER,
+ _HSE_KER_DIV2,
+ _CSI_KER,
+ _PLL1_P,
+ _PLL1_Q,
+ _PLL1_R,
+ _PLL2_P,
+ _PLL2_Q,
+ _PLL2_R,
+ _PLL3_P,
+ _PLL3_Q,
+ _PLL3_R,
+ _PLL4_P,
+ _PLL4_Q,
+ _PLL4_R,
+ _ACLK,
+ _PCLK1,
+ _PCLK2,
+ _PCLK3,
+ _PCLK4,
+ _PCLK5,
+ _HCLK6,
+ _HCLK2,
+ _CK_PER,
+ _CK_MPU,
+ _CK_MCU,
+ _DSI_PHY,
+ _USB_PHY_48,
+ _PARENT_NB,
+ _UNKNOWN_ID = 0xff,
+};
+
+#if defined(CONFIG_XPL_BUILD)
+
+#define MAX_HSI_HZ 64000000
+
+/* TIMEOUT */
+#define TIMEOUT_200MS 200000
+#define TIMEOUT_1S 1000000
+
+/* STGEN registers */
+#define STGENC_CNTCR 0x00
+#define STGENC_CNTSR 0x04
+#define STGENC_CNTCVL 0x08
+#define STGENC_CNTCVU 0x0C
+#define STGENC_CNTFID0 0x20
+
+#define STGENC_CNTCR_EN BIT(0)
+
+enum stm32mp1_clksrc_id {
+ CLKSRC_MPU,
+ CLKSRC_AXI,
+ CLKSRC_MLAHB,
+ CLKSRC_PLL12,
+ CLKSRC_PLL3,
+ CLKSRC_PLL4,
+ CLKSRC_RTC,
+ CLKSRC_MCO1,
+ CLKSRC_MCO2,
+ CLKSRC_NB
+};
+
+enum stm32mp1_clkdiv_id {
+ CLKDIV_AXI,
+ CLKDIV_MLAHB,
+ CLKDIV_APB1,
+ CLKDIV_APB2,
+ CLKDIV_APB3,
+ CLKDIV_APB4,
+ CLKDIV_APB5,
+ CLKDIV_APB6,
+ CLKDIV_RTC,
+ CLKDIV_NB
+};
+
+enum stm32mp1_pll_id {
+ _PLL1,
+ _PLL2,
+ _PLL3,
+ _PLL4,
+ _PLL_NB
+};
+
+enum stm32mp1_div_id {
+ _DIV_P,
+ _DIV_Q,
+ _DIV_R,
+ _DIV_NB,
+};
+
+/* define characteristic of PLL according type */
+#define DIVM_MIN 1
+#define DIVM_MAX 63
+#define DIVN_MIN 24
+#define DIVP_MIN 0
+#define DIVP_MAX 127
+#define FRAC_MAX 8192
+
+#define PLL2000_VCO_MIN 992000000
+#define PLL2000_VCO_MAX 2000000000
+
+enum stm32mp1_pllcfg {
+ PLLCFG_M,
+ PLLCFG_N,
+ PLLCFG_P,
+ PLLCFG_Q,
+ PLLCFG_R,
+ PLLCFG_O,
+ PLLCFG_NB
+};
+
+enum stm32mp1_pllcsg {
+ PLLCSG_MOD_PER,
+ PLLCSG_INC_STEP,
+ PLLCSG_SSCG_MODE,
+ PLLCSG_NB
+};
+
+enum stm32mp1_plltype {
+ PLL_800,
+ PLL_1600,
+ PLL_2000,
+ PLL_TYPE_NB
+};
+
+struct stm32mp1_pll {
+ u8 refclk_min;
+ u8 refclk_max;
+ u8 divn_max;
+};
+
+#define REFCLK_SIZE 4
+struct stm32mp1_clk_pll {
+ enum stm32mp1_plltype plltype;
+ u16 rckxselr;
+ u16 pllxcfgr1;
+ u16 pllxcfgr2;
+ u16 pllxfracr;
+ u16 pllxcr;
+ u16 pllxcsgr;
+ u8 refclk[REFCLK_SIZE];
+};
+
+static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = {
+ [PLL_800] = {
+ .refclk_min = 4,
+ .refclk_max = 16,
+ .divn_max = 99,
+ },
+ [PLL_1600] = {
+ .refclk_min = 8,
+ .refclk_max = 16,
+ .divn_max = 199,
+ },
+ [PLL_2000] = {
+ .refclk_min = 8,
+ .refclk_max = 16,
+ .divn_max = 99,
+ },
+};
+
+#define STM32MP1_CLK_PLL(idx, type, off1, off2, off3, off4, off5, off6,\
+ p1, p2, p3, p4) \
+ [(idx)] = { \
+ .plltype = (type), \
+ .rckxselr = (off1), \
+ .pllxcfgr1 = (off2), \
+ .pllxcfgr2 = (off3), \
+ .pllxfracr = (off4), \
+ .pllxcr = (off5), \
+ .pllxcsgr = (off6), \
+ .refclk[0] = (p1), \
+ .refclk[1] = (p2), \
+ .refclk[2] = (p3), \
+ .refclk[3] = (p4), \
+ }
+
+static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = {
+ STM32MP1_CLK_PLL(_PLL1, PLL_2000,
+ RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2,
+ RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR,
+ _HSI, _HSE, _UNKNOWN_ID, _UNKNOWN_ID),
+ STM32MP1_CLK_PLL(_PLL2, PLL_1600,
+ RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2,
+ RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR,
+ _HSI, _HSE, _UNKNOWN_ID, _UNKNOWN_ID),
+ STM32MP1_CLK_PLL(_PLL3, PLL_800,
+ RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2,
+ RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR,
+ _HSI, _HSE, _CSI, _UNKNOWN_ID),
+ STM32MP1_CLK_PLL(_PLL4, PLL_800,
+ RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2,
+ RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR,
+ _HSI, _HSE, _CSI, _I2S_CKIN),
};
+static ulong stm32mp1_clk_get_fixed(struct stm32mp_rcc_priv *priv, int idx)
+{
+ if (idx >= NB_OSC) {
+ log_debug("clk id %d not found\n", idx);
+ return 0;
+ }
+
+ return clk_get_rate(&priv->osc_clk[idx]);
+}
+
+bool stm32mp1_supports_opp(u32 opp_id, u32 cpu_type)
+{
+ /* 650 MHz is always supported */
+ if (opp_id == 1)
+ return true;
+
+ /*
+ * 1000 MHz is supported on STM32MP13xDxx and STM32MP13xFxx,
+ * which all have bit 11 i.e. 0x800 set in CPU ID.
+ */
+ if (opp_id == 2)
+ return !!(cpu_type & BIT(11));
+
+ /* Any other OPP is invalid. */
+ return false;
+}
+
+__weak void board_vddcore_init(u32 voltage_mv)
+{
+}
+
+/*
+ * gets OPP parameters (frequency in KHz and voltage in mV) from
+ * an OPP table subnode. Platform HW support capabilities are also checked.
+ * Returns 0 on success and a negative FDT error code on failure.
+ */
+static int stm32mp1_get_opp(u32 cpu_type, ofnode subnode,
+ u32 *freq_khz, u32 *voltage_mv)
+{
+ u32 opp_hw;
+ u64 read_freq_64;
+ u32 read_voltage_32;
+
+ *freq_khz = 0;
+ *voltage_mv = 0;
+
+ opp_hw = ofnode_read_u32_default(subnode, "opp-supported-hw", 0);
+ if (opp_hw)
+ if (!stm32mp1_supports_opp(opp_hw, cpu_type))
+ return -FDT_ERR_BADVALUE;
+
+ read_freq_64 = ofnode_read_u64_default(subnode, "opp-hz", 0) /
+ 1000ULL;
+ read_voltage_32 = ofnode_read_u32_default(subnode, "opp-microvolt", 0) /
+ 1000U;
+
+ if (!read_voltage_32 || !read_freq_64)
+ return -FDT_ERR_NOTFOUND;
+
+ /* Frequency value expressed in KHz must fit on 32 bits */
+ if (read_freq_64 > U32_MAX)
+ return -FDT_ERR_BADVALUE;
+
+ /* Millivolt value must fit on 16 bits */
+ if (read_voltage_32 > U16_MAX)
+ return -FDT_ERR_BADVALUE;
+
+ *freq_khz = (u32)read_freq_64;
+ *voltage_mv = read_voltage_32;
+
+ return 0;
+}
+
+/*
+ * parses OPP table in DT and finds the parameters for the
+ * highest frequency supported by the HW platform.
+ * Returns 0 on success and a negative FDT error code on failure.
+ */
+int stm32mp1_get_max_opp_freq(struct stm32mp_rcc_priv *priv, u64 *freq_hz)
+{
+ ofnode node, subnode;
+ int ret;
+ u32 freq = 0U, voltage = 0U;
+ u32 cpu_type = get_cpu_type();
+
+ node = ofnode_by_compatible(ofnode_null(), "operating-points-v2");
+ if (!ofnode_valid(node))
+ return -FDT_ERR_NOTFOUND;
+
+ ofnode_for_each_subnode(subnode, node) {
+ unsigned int read_freq;
+ unsigned int read_voltage;
+
+ ret = stm32mp1_get_opp(cpu_type, subnode,
+ &read_freq, &read_voltage);
+ if (ret)
+ continue;
+
+ if (read_freq > freq) {
+ freq = read_freq;
+ voltage = read_voltage;
+ }
+ }
+
+ if (!freq || !voltage)
+ return -FDT_ERR_NOTFOUND;
+
+ *freq_hz = (u64)1000U * freq;
+ board_vddcore_init(voltage);
+
+ return 0;
+}
+
+static int stm32mp1_pll1_opp(struct stm32mp_rcc_priv *priv, int clksrc,
+ u32 *pllcfg, u32 *fracv)
+{
+ u32 post_divm;
+ u32 input_freq;
+ u64 output_freq;
+ u64 freq;
+ u64 vco;
+ u32 divm, divn, divp, frac;
+ int i, ret;
+ u32 diff;
+ u32 best_diff = U32_MAX;
+
+ /* PLL1 is 2000 */
+ const u32 DIVN_MAX = stm32mp1_pll[PLL_2000].divn_max;
+ const u32 POST_DIVM_MIN = stm32mp1_pll[PLL_2000].refclk_min * 1000000U;
+ const u32 POST_DIVM_MAX = stm32mp1_pll[PLL_2000].refclk_max * 1000000U;
+
+ ret = stm32mp1_get_max_opp_freq(priv, &output_freq);
+ if (ret) {
+ log_debug("PLL1 OPP configuration not found (%d).\n", ret);
+ return ret;
+ }
+
+ switch (clksrc) {
+ case CLK_PLL12_HSI:
+ input_freq = stm32mp1_clk_get_fixed(priv, _HSI);
+ break;
+ case CLK_PLL12_HSE:
+ input_freq = stm32mp1_clk_get_fixed(priv, _HSE);
+ break;
+ default:
+ return -EINTR;
+ }
+
+ /* Following parameters have always the same value */
+ pllcfg[PLLCFG_Q] = 0;
+ pllcfg[PLLCFG_R] = 0;
+ pllcfg[PLLCFG_O] = PQR(1, 1, 1);
+
+ for (divm = DIVM_MAX; divm >= DIVM_MIN; divm--) {
+ post_divm = (u32)(input_freq / (divm + 1));
+ if (post_divm < POST_DIVM_MIN || post_divm > POST_DIVM_MAX)
+ continue;
+
+ for (divp = DIVP_MIN; divp <= DIVP_MAX; divp++) {
+ freq = output_freq * (divm + 1) * (divp + 1);
+ divn = (u32)((freq / input_freq) - 1);
+ if (divn < DIVN_MIN || divn > DIVN_MAX)
+ continue;
+
+ frac = (u32)(((freq * FRAC_MAX) / input_freq) -
+ ((divn + 1) * FRAC_MAX));
+ /* 2 loops to refine the fractional part */
+ for (i = 2; i != 0; i--) {
+ if (frac > FRAC_MAX)
+ break;
+
+ vco = (post_divm * (divn + 1)) +
+ ((post_divm * (u64)frac) /
+ FRAC_MAX);
+ if (vco < (PLL2000_VCO_MIN / 2) ||
+ vco > (PLL2000_VCO_MAX / 2)) {
+ frac++;
+ continue;
+ }
+ freq = vco / (divp + 1);
+ if (output_freq < freq)
+ diff = (u32)(freq - output_freq);
+ else
+ diff = (u32)(output_freq - freq);
+ if (diff < best_diff) {
+ pllcfg[PLLCFG_M] = divm;
+ pllcfg[PLLCFG_N] = divn;
+ pllcfg[PLLCFG_P] = divp;
+ *fracv = frac;
+
+ if (diff == 0) {
+ return 0;
+ }
+
+ best_diff = diff;
+ }
+ frac++;
+ }
+ }
+ }
+
+ if (best_diff == U32_MAX)
+ return -1;
+
+ return 0;
+}
+
+static void stm32mp1_ls_osc_set(int enable, fdt_addr_t rcc, u32 offset,
+ u32 mask_on)
+{
+ u32 address = rcc + offset;
+
+ if (enable)
+ setbits_le32(address, mask_on);
+ else
+ clrbits_le32(address, mask_on);
+}
+
+static void stm32mp1_hs_ocs_set(int enable, fdt_addr_t rcc, u32 mask_on)
+{
+ writel(mask_on, rcc + (enable ? RCC_OCENSETR : RCC_OCENCLRR));
+}
+
+static int stm32mp1_osc_wait(int enable, fdt_addr_t rcc, u32 offset,
+ u32 mask_rdy)
+{
+ u32 mask_test = 0;
+ u32 address = rcc + offset;
+ u32 val;
+ int ret;
+
+ if (enable)
+ mask_test = mask_rdy;
+
+ ret = readl_poll_timeout(address, val,
+ (val & mask_rdy) == mask_test,
+ TIMEOUT_1S);
+
+ if (ret)
+ log_err("OSC %x @ %x timeout for enable=%d : 0x%x\n",
+ mask_rdy, address, enable, readl(address));
+
+ return ret;
+}
+
+static void stm32mp1_lse_enable(fdt_addr_t rcc, int bypass, int digbyp,
+ u32 lsedrv)
+{
+ u32 value;
+
+ if (digbyp)
+ setbits_le32(rcc + RCC_BDCR, RCC_BDCR_DIGBYP);
+
+ if (bypass || digbyp)
+ setbits_le32(rcc + RCC_BDCR, RCC_BDCR_LSEBYP);
+
+ /*
+ * warning: not recommended to switch directly from "high drive"
+ * to "medium low drive", and vice-versa.
+ */
+ value = (readl(rcc + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK)
+ >> RCC_BDCR_LSEDRV_SHIFT;
+
+ while (value != lsedrv) {
+ if (value > lsedrv)
+ value--;
+ else
+ value++;
+
+ clrsetbits_le32(rcc + RCC_BDCR,
+ RCC_BDCR_LSEDRV_MASK,
+ value << RCC_BDCR_LSEDRV_SHIFT);
+ }
+
+ stm32mp1_ls_osc_set(1, rcc, RCC_BDCR, RCC_BDCR_LSEON);
+}
+
+static void stm32mp1_lse_wait(fdt_addr_t rcc)
+{
+ stm32mp1_osc_wait(1, rcc, RCC_BDCR, RCC_BDCR_LSERDY);
+}
+
+static void stm32mp1_lsi_set(fdt_addr_t rcc, int enable)
+{
+ stm32mp1_ls_osc_set(enable, rcc, RCC_RDLSICR, RCC_RDLSICR_LSION);
+ stm32mp1_osc_wait(enable, rcc, RCC_RDLSICR, RCC_RDLSICR_LSIRDY);
+}
+
+static void stm32mp1_hse_enable(fdt_addr_t rcc, int bypass, int digbyp, int css)
+{
+ if (digbyp)
+ writel(RCC_OCENR_DIGBYP, rcc + RCC_OCENSETR);
+ if (bypass || digbyp)
+ writel(RCC_OCENR_HSEBYP, rcc + RCC_OCENSETR);
+
+ stm32mp1_hs_ocs_set(1, rcc, RCC_OCENR_HSEON);
+ stm32mp1_osc_wait(1, rcc, RCC_OCRDYR, RCC_OCRDYR_HSERDY);
+
+ if (css)
+ writel(RCC_OCENR_HSECSSON, rcc + RCC_OCENSETR);
+}
+
+static void stm32mp1_csi_set(fdt_addr_t rcc, int enable)
+{
+ stm32mp1_hs_ocs_set(enable, rcc, RCC_OCENR_CSION);
+ stm32mp1_osc_wait(enable, rcc, RCC_OCRDYR, RCC_OCRDYR_CSIRDY);
+}
+
+static void stm32mp1_hsi_set(fdt_addr_t rcc, int enable)
+{
+ stm32mp1_hs_ocs_set(enable, rcc, RCC_OCENR_HSION);
+ stm32mp1_osc_wait(enable, rcc, RCC_OCRDYR, RCC_OCRDYR_HSIRDY);
+}
+
+static int stm32mp1_set_hsidiv(fdt_addr_t rcc, u8 hsidiv)
+{
+ u32 address = rcc + RCC_OCRDYR;
+ u32 val;
+ int ret;
+
+ clrsetbits_le32(rcc + RCC_HSICFGR,
+ RCC_HSICFGR_HSIDIV_MASK,
+ RCC_HSICFGR_HSIDIV_MASK & hsidiv);
+
+ ret = readl_poll_timeout(address, val,
+ val & RCC_OCRDYR_HSIDIVRDY,
+ TIMEOUT_200MS);
+ if (ret)
+ log_err("HSIDIV failed @ 0x%x: 0x%x\n",
+ address, readl(address));
+
+ return ret;
+}
+
+static int stm32mp1_hsidiv(fdt_addr_t rcc, ulong hsifreq)
+{
+ u8 hsidiv;
+ u32 hsidivfreq = MAX_HSI_HZ;
+
+ for (hsidiv = 0; hsidiv < 4; hsidiv++,
+ hsidivfreq = hsidivfreq / 2)
+ if (hsidivfreq == hsifreq)
+ break;
+
+ if (hsidiv == 4) {
+ log_err("hsi frequency invalid");
+ return -1;
+ }
+
+ if (hsidiv > 0)
+ return stm32mp1_set_hsidiv(rcc, hsidiv);
+
+ return 0;
+}
+
+static void pll_start(struct stm32mp_rcc_priv *priv, int pll_id)
+{
+ clrsetbits_le32((u32)(priv->base) + stm32mp1_clk_pll[pll_id].pllxcr,
+ RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN |
+ RCC_PLLNCR_DIVREN,
+ RCC_PLLNCR_PLLON);
+}
+
+static int pll_output(struct stm32mp_rcc_priv *priv, int pll_id, int output)
+{
+ u32 pllxcr = (u32)(priv->base) + stm32mp1_clk_pll[pll_id].pllxcr;
+ u32 val;
+ int ret;
+
+ ret = readl_poll_timeout(pllxcr, val, val & RCC_PLLNCR_PLLRDY,
+ TIMEOUT_200MS);
+
+ if (ret) {
+ log_err("PLL%d start failed @ 0x%x: 0x%x\n",
+ pll_id, pllxcr, readl(pllxcr));
+ return ret;
+ }
+
+ /* start the requested output */
+ setbits_le32(pllxcr, output << RCC_PLLNCR_DIVEN_SHIFT);
+
+ return 0;
+}
+
+static int pll_stop(struct stm32mp_rcc_priv *priv, int pll_id)
+{
+ u32 pllxcr = (u32)(priv->base) + stm32mp1_clk_pll[pll_id].pllxcr;
+ u32 val;
+
+ /* stop all output */
+ clrbits_le32(pllxcr,
+ RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | RCC_PLLNCR_DIVREN);
+
+ /* stop PLL */
+ clrbits_le32(pllxcr, RCC_PLLNCR_PLLON);
+
+ /* wait PLL stopped */
+ return readl_poll_timeout(pllxcr, val, (val & RCC_PLLNCR_PLLRDY) == 0,
+ TIMEOUT_200MS);
+}
+
+static void pll_config_output(struct stm32mp_rcc_priv *priv,
+ int pll_id, u32 *pllcfg)
+{
+ fdt_addr_t rcc = (u32)(priv->base);
+ u32 value;
+
+ value = (pllcfg[PLLCFG_P] << RCC_PLLNCFGR2_DIVP_SHIFT)
+ & RCC_PLLNCFGR2_DIVP_MASK;
+ value |= (pllcfg[PLLCFG_Q] << RCC_PLLNCFGR2_DIVQ_SHIFT)
+ & RCC_PLLNCFGR2_DIVQ_MASK;
+ value |= (pllcfg[PLLCFG_R] << RCC_PLLNCFGR2_DIVR_SHIFT)
+ & RCC_PLLNCFGR2_DIVR_MASK;
+ writel(value, rcc + stm32mp1_clk_pll[pll_id].pllxcfgr2);
+}
+
+static int pll_config(struct stm32mp_rcc_priv *priv, int pll_id,
+ u32 *pllcfg, u32 fracv)
+{
+ fdt_addr_t rcc = (u32)(priv->base);
+ enum stm32mp1_plltype type = stm32mp1_clk_pll[pll_id].plltype;
+ int src;
+ ulong refclk;
+ u8 ifrge = 0;
+ u32 value;
+
+ src = readl((u32)(priv->base) + stm32mp1_clk_pll[pll_id].rckxselr) & RCC_SELR_SRC_MASK;
+ refclk = stm32mp1_clk_get_fixed(priv, stm32mp1_clk_pll[pll_id].refclk[src]) /
+ (pllcfg[PLLCFG_M] + 1);
+
+ if (refclk < (stm32mp1_pll[type].refclk_min * 1000000) ||
+ refclk > (stm32mp1_pll[type].refclk_max * 1000000)) {
+ log_err("invalid refclk = %x\n", (u32)refclk);
+ return -EINVAL;
+ }
+
+
+ if (type == PLL_800 && refclk >= 8000000)
+ ifrge = 1;
+
+ value = (pllcfg[PLLCFG_N] << RCC_PLLNCFGR1_DIVN_SHIFT)
+ & RCC_PLLNCFGR1_DIVN_MASK;
+ value |= (pllcfg[PLLCFG_M] << RCC_PLLNCFGR1_DIVM_SHIFT)
+ & RCC_PLLNCFGR1_DIVM_MASK;
+ value |= (ifrge << RCC_PLLNCFGR1_IFRGE_SHIFT)
+ & RCC_PLLNCFGR1_IFRGE_MASK;
+ writel(value, rcc + stm32mp1_clk_pll[pll_id].pllxcfgr1);
+
+ /* fractional configuration: load sigma-delta modulator (SDM) */
+
+ /* Write into FRACV the new fractional value , and FRACLE to 0 */
+ writel(fracv << RCC_PLLNFRACR_FRACV_SHIFT,
+ rcc + stm32mp1_clk_pll[pll_id].pllxfracr);
+
+ /* Write FRACLE to 1 : FRACV value is loaded into the SDM */
+ setbits_le32(rcc + stm32mp1_clk_pll[pll_id].pllxfracr,
+ RCC_PLLNFRACR_FRACLE);
+
+ pll_config_output(priv, pll_id, pllcfg);
+
+ return 0;
+}
+
+static void pll_csg(struct stm32mp_rcc_priv *priv, int pll_id, u32 *csg)
+{
+ u32 pllxcsg;
+
+ pllxcsg = ((csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) &
+ RCC_PLLNCSGR_MOD_PER_MASK) |
+ ((csg[PLLCSG_INC_STEP] << RCC_PLLNCSGR_INC_STEP_SHIFT) &
+ RCC_PLLNCSGR_INC_STEP_MASK) |
+ ((csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) &
+ RCC_PLLNCSGR_SSCG_MODE_MASK);
+
+ writel(pllxcsg, (u32)(priv->base) + stm32mp1_clk_pll[pll_id].pllxcsgr);
+
+ setbits_le32((u32)(priv->base) + stm32mp1_clk_pll[pll_id].pllxcr, RCC_PLLNCR_SSCG_CTRL);
+}
+
+static ulong pll_get_fref_ck(struct stm32mp_rcc_priv *priv,
+ int pll_id)
+{
+ u32 selr;
+ int src;
+
+ /* Get current refclk */
+ selr = readl(priv->base + stm32mp1_clk_pll[pll_id].rckxselr);
+ src = selr & RCC_SELR_SRC_MASK;
+
+ return stm32mp1_clk_get_fixed(priv, stm32mp1_clk_pll[pll_id].refclk[src]);
+}
+
+static __maybe_unused int pll_set_rate(struct udevice *dev,
+ int pll_id,
+ int div_id,
+ unsigned long clk_rate)
+{
+ struct stm32mp_rcc_priv *priv = dev_get_priv(dev);
+ unsigned int pllcfg[PLLCFG_NB];
+ ofnode plloff;
+ char name[12];
+ enum stm32mp1_plltype type = stm32mp1_clk_pll[pll_id].plltype;
+ int divm, divn, divy;
+ int ret;
+ ulong fck_ref;
+ u32 fracv;
+ u64 value;
+
+ if (div_id > _DIV_NB)
+ return -EINVAL;
+
+ sprintf(name, "st,pll@%d", pll_id);
+ plloff = dev_read_subnode(dev, name);
+ if (!ofnode_valid(plloff))
+ return -FDT_ERR_NOTFOUND;
+
+ ret = ofnode_read_u32_array(plloff, "cfg",
+ pllcfg, PLLCFG_NB);
+ if (ret < 0)
+ return -FDT_ERR_NOTFOUND;
+
+ fck_ref = pll_get_fref_ck(priv, pll_id);
+
+ divm = pllcfg[PLLCFG_M];
+ /* select output divider = 0: for _DIV_P, 1:_DIV_Q 2:_DIV_R */
+ divy = pllcfg[PLLCFG_P + div_id];
+
+ /* For: PLL1 & PLL2 => VCO is * 2 but ck_pll_y is also / 2
+ * So same final result than PLL2 et 4
+ * with FRACV
+ * Fck_pll_y = Fck_ref * ((DIVN + 1) + FRACV / 2^13)
+ * / (DIVy + 1) * (DIVM + 1)
+ * value = (DIVN + 1) * 2^13 + FRACV / 2^13
+ * = Fck_pll_y (DIVy + 1) * (DIVM + 1) * 2^13 / Fck_ref
+ */
+ value = ((u64)clk_rate * (divy + 1) * (divm + 1)) << 13;
+ value = lldiv(value, fck_ref);
+
+ divn = (value >> 13) - 1;
+ if (divn < DIVN_MIN ||
+ divn > stm32mp1_pll[type].divn_max) {
+ dev_err(dev, "divn invalid = %d", divn);
+ return -EINVAL;
+ }
+ fracv = value - ((divn + 1) << 13);
+ pllcfg[PLLCFG_N] = divn;
+
+ /* reconfigure PLL */
+ pll_stop(priv, pll_id);
+ pll_config(priv, pll_id, pllcfg, fracv);
+ pll_start(priv, pll_id);
+ pll_output(priv, pll_id, pllcfg[PLLCFG_O]);
+
+ return 0;
+}
+
+static int set_clksrc(struct stm32mp_rcc_priv *priv, unsigned int clksrc)
+{
+ u32 address = (u32)(priv->base);
+ u32 mux = (clksrc & MUX_ID_MASK) >> MUX_ID_SHIFT;
+ u32 val;
+ int ret;
+
+ /* List of relevant muxes to keep the size down */
+ if (mux == MUX_PLL12)
+ address += RCC_RCK12SELR;
+ else if (mux == MUX_PLL3)
+ address += RCC_RCK3SELR;
+ else if (mux == MUX_PLL4)
+ address += RCC_RCK4SELR;
+ else if (mux == MUX_MPU)
+ address += RCC_MPCKSELR;
+ else if (mux == MUX_AXI)
+ address += RCC_ASSCKSELR;
+ else if (mux == MUX_MLAHB)
+ address += RCC_MSSCKSELR;
+ else if (mux == MUX_CKPER)
+ address += RCC_CPERCKSELR;
+ else
+ return -EINVAL;
+
+ clrsetbits_le32(address, RCC_SELR_SRC_MASK, clksrc & RCC_SELR_SRC_MASK);
+ ret = readl_poll_timeout(address, val, val & RCC_SELR_SRCRDY,
+ TIMEOUT_200MS);
+ if (ret)
+ log_err("CLKSRC %x start failed @ 0x%x: 0x%x\n",
+ clksrc, address, readl(address));
+
+ return ret;
+}
+
+static void stgen_config(struct stm32mp_rcc_priv *priv)
+{
+ u32 stgenc, cntfid0;
+ ulong rate = clk_get_rate(&priv->osc_clk[_HSI]);
+ stgenc = STM32_STGEN_BASE;
+ cntfid0 = readl(stgenc + STGENC_CNTFID0);
+
+ if (cntfid0 != rate) {
+ u64 counter;
+
+ log_debug("System Generic Counter (STGEN) update\n");
+ clrbits_le32(stgenc + STGENC_CNTCR, STGENC_CNTCR_EN);
+ counter = (u64)readl(stgenc + STGENC_CNTCVL);
+ counter |= ((u64)(readl(stgenc + STGENC_CNTCVU))) << 32;
+ counter = lldiv(counter * (u64)rate, cntfid0);
+ writel((u32)counter, stgenc + STGENC_CNTCVL);
+ writel((u32)(counter >> 32), stgenc + STGENC_CNTCVU);
+ writel(rate, stgenc + STGENC_CNTFID0);
+ setbits_le32(stgenc + STGENC_CNTCR, STGENC_CNTCR_EN);
+
+ __asm__ volatile("mcr p15, 0, %0, c14, c0, 0" : : "r" (rate));
+
+ /* need to update gd->arch.timer_rate_hz with new frequency */
+ timer_init();
+ }
+}
+
+static int set_clkdiv(unsigned int clkdiv, u32 address)
+{
+ u32 val;
+ int ret;
+
+
+ clrsetbits_le32(address, RCC_DIVR_DIV_MASK, clkdiv & RCC_DIVR_DIV_MASK);
+ ret = readl_poll_timeout(address, val, val & RCC_DIVR_DIVRDY,
+ TIMEOUT_200MS);
+ if (ret)
+ log_err("CLKDIV %x start failed @ 0x%x: 0x%x\n",
+ clkdiv, address, readl(address));
+
+ return ret;
+}
+
+static void set_rtcsrc(struct stm32mp_rcc_priv *priv,
+ unsigned int clksrc,
+ int lse_css)
+{
+ u32 address = (u32)(priv->base) + RCC_BDCR;
+
+ if (readl(address) & RCC_BDCR_RTCCKEN)
+ goto skip_rtc;
+
+ if (clksrc == CLK_RTC_DISABLED)
+ goto skip_rtc;
+
+ clrsetbits_le32(address,
+ RCC_BDCR_RTCSRC_MASK,
+ clksrc << RCC_BDCR_RTCSRC_SHIFT);
+
+ setbits_le32(address, RCC_BDCR_RTCCKEN);
+
+skip_rtc:
+ if (lse_css)
+ setbits_le32(address, RCC_BDCR_LSECSSON);
+}
+
+static void pkcs_config(struct stm32mp_rcc_priv *priv, u32 pkcs)
+{
+ u32 mux = (pkcs & MUX_ID_MASK) >> MUX_ID_SHIFT;
+ u32 address = (u32)(priv->base) + stm32mp13_muxes[mux].reg_off;
+ u32 mask = (BIT(stm32mp13_muxes[mux].width) - 1) << stm32mp13_muxes[mux].shift;
+ u32 value = (pkcs << stm32mp13_muxes[mux].shift) & mask;
+
+ clrsetbits_le32(address, mask, value);
+}
+
+static int stm32mp1_clktree(struct udevice *dev)
+{
+ struct stm32mp_rcc_priv *priv = dev_get_priv(dev);
+ fdt_addr_t rcc = (u32)(priv->base);
+ unsigned int clksrc[CLKSRC_NB];
+ unsigned int clkdiv[CLKDIV_NB];
+ unsigned int pllcfg[_PLL_NB][PLLCFG_NB];
+ unsigned int pllfracv[_PLL_NB];
+ unsigned int pllcsg[_PLL_NB][PLLCSG_NB];
+ bool pllcfg_valid[_PLL_NB];
+ bool pllcsg_set[_PLL_NB];
+ int ret;
+ int i, len;
+ int lse_css = 0;
+ const u32 *pkcs_cell;
+
+ /* check mandatory field */
+ ret = dev_read_u32_array(dev, "st,clksrc", clksrc, CLKSRC_NB);
+ if (ret < 0) {
+ dev_dbg(dev, "field st,clksrc invalid: error %d\n", ret);
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ ret = dev_read_u32_array(dev, "st,clkdiv", clkdiv, CLKDIV_NB);
+ if (ret < 0) {
+ dev_dbg(dev, "field st,clkdiv invalid: error %d\n", ret);
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ /* check mandatory field in each pll */
+ for (i = 0; i < _PLL_NB; i++) {
+ char name[12];
+ ofnode node;
+
+ sprintf(name, "st,pll@%d", i);
+ node = dev_read_subnode(dev, name);
+ pllcfg_valid[i] = ofnode_valid(node);
+ pllcsg_set[i] = false;
+ if (pllcfg_valid[i]) {
+ dev_dbg(dev, "DT for PLL %d @ %s\n", i, name);
+ ret = ofnode_read_u32_array(node, "cfg",
+ pllcfg[i], PLLCFG_NB);
+ if (ret < 0) {
+ dev_dbg(dev, "field cfg invalid: error %d\n", ret);
+ return -FDT_ERR_NOTFOUND;
+ }
+ pllfracv[i] = ofnode_read_u32_default(node, "frac", 0);
+
+ ret = ofnode_read_u32_array(node, "csg", pllcsg[i],
+ PLLCSG_NB);
+ if (!ret) {
+ pllcsg_set[i] = true;
+ } else if (ret != -FDT_ERR_NOTFOUND) {
+ dev_dbg(dev, "invalid csg node for pll@%d res=%d\n",
+ i, ret);
+ return ret;
+ }
+ } else if (i == _PLL1) {
+ /* use OPP for PLL1 for A7 CPU */
+ dev_dbg(dev, "DT for PLL %d with OPP\n", i);
+ ret = stm32mp1_pll1_opp(priv,
+ clksrc[CLKSRC_PLL12],
+ pllcfg[i],
+ &pllfracv[i]);
+ if (ret) {
+ dev_dbg(dev, "PLL %d with OPP error = %d\n", i, ret);
+ return ret;
+ }
+ pllcfg_valid[i] = true;
+ }
+ }
+
+ dev_dbg(dev, "switch ON osillator\n");
+ /*
+ * switch ON oscillator found in device-tree,
+ * HSI already ON after bootrom
+ */
+ if (clk_valid(&priv->osc_clk[_LSI]))
+ stm32mp1_lsi_set(rcc, 1);
+
+ if (clk_valid(&priv->osc_clk[_LSE])) {
+ int bypass, digbyp;
+ u32 lsedrv;
+ struct udevice *dev = priv->osc_clk[_LSE].dev;
+
+ bypass = dev_read_bool(dev, "st,bypass");
+ digbyp = dev_read_bool(dev, "st,digbypass");
+ lse_css = dev_read_bool(dev, "st,css");
+ lsedrv = dev_read_u32_default(dev, "st,drive",
+ LSEDRV_MEDIUM_HIGH);
+
+ stm32mp1_lse_enable(rcc, bypass, digbyp, lsedrv);
+ }
+
+
+ if (clk_valid(&priv->osc_clk[_HSE])) {
+ int bypass, digbyp, css;
+ struct udevice *dev = priv->osc_clk[_HSE].dev;
+
+ bypass = dev_read_bool(dev, "st,bypass");
+ digbyp = dev_read_bool(dev, "st,digbypass");
+ css = dev_read_bool(dev, "st,css");
+
+ stm32mp1_hse_enable(rcc, bypass, digbyp, css);
+ }
+
+ /* CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR)
+ * => switch on CSI even if node is not present in device tree
+ */
+ stm32mp1_csi_set(rcc, 1);
+
+ /* come back to HSI */
+ dev_dbg(dev, "come back to HSI\n");
+ set_clksrc(priv, CLK_MPU_HSI);
+ set_clksrc(priv, CLK_AXI_HSI);
+ set_clksrc(priv, CLK_MLAHBS_HSI);
+
+ dev_dbg(dev, "pll stop\n");
+ for (i = 0; i < _PLL_NB; i++)
+ pll_stop(priv, i);
+
+ /* configure HSIDIV */
+ dev_dbg(dev, "configure HSIDIV\n");
+ if (clk_valid(&priv->osc_clk[_HSI])) {
+ stm32mp1_hsidiv(rcc, clk_get_rate(&priv->osc_clk[_HSI]));
+ stgen_config(priv);
+ }
+
+ /* select DIV */
+ dev_dbg(dev, "select DIV\n");
+ /* no ready bit when MPUSRC != CLK_MPU_PLL1P_DIV, MPUDIV is disabled */
+ set_clkdiv(clkdiv[CLKDIV_AXI], rcc + RCC_AXIDIVR);
+ set_clkdiv(clkdiv[CLKDIV_APB4], rcc + RCC_APB4DIVR);
+ set_clkdiv(clkdiv[CLKDIV_APB5], rcc + RCC_APB5DIVR);
+ set_clkdiv(clkdiv[CLKDIV_APB6], rcc + RCC_APB6DIVR);
+ set_clkdiv(clkdiv[CLKDIV_APB1], rcc + RCC_APB1DIVR);
+ set_clkdiv(clkdiv[CLKDIV_APB2], rcc + RCC_APB2DIVR);
+ set_clkdiv(clkdiv[CLKDIV_APB3], rcc + RCC_APB3DIVR);
+
+ /* no ready bit for RTC */
+ writel(clkdiv[CLKDIV_RTC] & RCC_DIVR_DIV_MASK, rcc + RCC_RTCDIVR);
+
+ /* configure PLLs source */
+ dev_dbg(dev, "configure PLLs source\n");
+ set_clksrc(priv, clksrc[CLKSRC_PLL12]);
+ set_clksrc(priv, clksrc[CLKSRC_PLL3]);
+ set_clksrc(priv, clksrc[CLKSRC_PLL4]);
+
+ /* configure and start PLLs */
+ dev_dbg(dev, "configure PLLs\n");
+ for (i = 0; i < _PLL_NB; i++) {
+ if (!pllcfg_valid[i])
+ continue;
+ dev_dbg(dev, "configure PLL %d\n", i);
+ pll_config(priv, i, pllcfg[i], pllfracv[i]);
+ if (pllcsg_set[i])
+ pll_csg(priv, i, pllcsg[i]);
+ pll_start(priv, i);
+ }
+
+ /* wait and start PLLs ouptut when ready */
+ for (i = 0; i < _PLL_NB; i++) {
+ if (!pllcfg_valid[i])
+ continue;
+ dev_dbg(dev, "output PLL %d\n", i);
+ pll_output(priv, i, pllcfg[i][PLLCFG_O]);
+ }
+
+ /* wait LSE ready before to use it */
+ if (clk_valid(&priv->osc_clk[_LSE]))
+ stm32mp1_lse_wait(rcc);
+
+ /* configure with expected clock source */
+ dev_dbg(dev, "CLKSRC\n");
+ set_clksrc(priv, clksrc[CLKSRC_MPU]);
+ set_clksrc(priv, clksrc[CLKSRC_AXI]);
+ set_clksrc(priv, clksrc[CLKSRC_MLAHB]);
+ set_rtcsrc(priv, clksrc[CLKSRC_RTC], lse_css);
+
+ /* configure PKCK */
+ dev_dbg(dev, "PKCK\n");
+ pkcs_cell = dev_read_prop(dev, "st,pkcs", &len);
+ if (pkcs_cell) {
+ bool ckper_disabled = false;
+
+ for (i = 0; i < len / sizeof(u32); i++) {
+ u32 pkcs = (u32)fdt32_to_cpu(pkcs_cell[i]);
+
+ if (pkcs == CLK_CKPER_DISABLED) {
+ ckper_disabled = true;
+ continue;
+ }
+ pkcs_config(priv, pkcs);
+ }
+ /* CKPER is source for some peripheral clock
+ * (FMC-NAND / QPSI-NOR) and switching source is allowed
+ * only if previous clock is still ON
+ * => deactivated CKPER only after switching clock
+ */
+ if (ckper_disabled)
+ pkcs_config(priv, CLK_CKPER_DISABLED);
+ }
+
+ /* STGEN clock source can change with CLK_STGEN_XXX */
+ stgen_config(priv);
+
+ dev_dbg(dev, "oscillator off\n");
+ /* switch OFF HSI if not found in device-tree */
+ if (!clk_valid(&priv->osc_clk[_HSI]))
+ stm32mp1_hsi_set(rcc, 0);
+
+ /* Software Self-Refresh mode (SSR) during DDR initilialization */
+ clrsetbits_le32((u32)(priv->base) + RCC_DDRITFCR,
+ RCC_DDRITFCR_DDRCKMOD_MASK,
+ RCC_DDRITFCR_DDRCKMOD_SSR <<
+ RCC_DDRITFCR_DDRCKMOD_SHIFT);
+
+ return 0;
+}
+#endif
+
+static int stm32mp1_osc_init(struct udevice *dev)
+{
+ struct stm32mp_rcc_priv *priv = dev_get_priv(dev);
+ fdt_addr_t base = dev_read_addr(dev->parent);
+ struct clk *ck;
+ int i;
+
+ const char *name[NB_OSC] = {
+ [_LSI] = "lsi",
+ [_LSE] = "lse",
+ [_HSI] = "hsi",
+ [_HSE] = "hse",
+ [_CSI] = "csi",
+ [_I2S_CKIN] = "i2s_ckin",
+ };
+
+ const struct {
+ const char *name;
+ const int rate;
+ } fixed_clk[] = {
+ { "bsec", 66625000 },
+ { "ck_axi", 266500000 },
+ { "ck_mlahb", 200000000 },
+ { "ck_mpu", 1000000000 },
+ { "ck_per", 24000000 },
+ { "ck_rtc", 32768 },
+ { "clk-hse-div2", 12000000 },
+ { "pclk1", 100000000 },
+ { "pclk2", 100000000 },
+ { "pclk3", 100000000 },
+ { "pclk4", 133250000 },
+ { "pclk5", 66625000 },
+ { "pclk6", 100000000 },
+ { "pll2_q", 266500000 },
+ { "pll2_r", 533000000 },
+ { "pll3_p", 200000000 },
+ { "pll3_q", 150000000 },
+ { "pll3_r", 200000000 },
+ { "pll4_p", 125000000 },
+ { "pll4_q", 83333333 },
+ { "pll4_r", 75000000 },
+ { "rtcapb", 66625000 },
+ { "timg1_ck", 200000000 },
+ { "timg2_ck", 200000000 },
+ { "timg3_ck", 200000000 },
+ };
+
+ if (base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->base = (void __iomem *)base;
+
+ for (i = 0; i < NB_OSC; i++) {
+ if (clk_get_by_name(dev, name[i], &priv->osc_clk[i]))
+ dev_dbg(dev, "No source clock \"%s\"\n", name[i]);
+ else
+ dev_dbg(dev, "%s clock rate: %luHz\n",
+ name[i], clk_get_rate(&priv->osc_clk[i]));
+ }
+
+ for (i = 0; i < ARRAY_SIZE(fixed_clk); i++) {
+ ck = clk_register_fixed_rate(NULL, fixed_clk[i].name, fixed_clk[i].rate);
+ if (!ck)
+ dev_dbg(dev, "Cannot register fixed clock \"%s\"\n", fixed_clk[i].name);
+ }
+
+ return 0;
+}
+#endif
+
static int stm32mp1_clk_probe(struct udevice *dev)
{
- struct udevice *scmi;
int err;
+#ifdef CONFIG_TFABOOT
+ struct udevice *scmi;
+
/* force SCMI probe to register all SCMI clocks */
uclass_get_device_by_driver(UCLASS_CLK, DM_DRIVER_GET(scmi_clock), &scmi);
+#else
+ err = stm32mp1_osc_init(dev);
+ if (err)
+ return err;
+
+#if defined(CONFIG_XPL_BUILD)
+ /* clock tree init is done only one time, before relocation */
+ if (!(gd->flags & GD_FLG_RELOC))
+ err = stm32mp1_clktree(dev);
+ if (err)
+ dev_err(dev, "clock tree initialization failed (%d)\n", err);
+#endif
+#endif
err = stm32_rcc_init(dev, &stm32mp13_data);
if (err)
@@ -815,6 +2012,7 @@ static int stm32mp1_clk_probe(struct udevice *dev)
/* DDRPHYC father */
gd->mem_clk = clk_stm32_get_rate_by_name("pll2_r");
+#ifndef CONFIG_XPL_BUILD
if (IS_ENABLED(CONFIG_DISPLAY_CPUINFO)) {
if (gd->flags & GD_FLG_RELOC) {
char buf[32];
@@ -827,6 +2025,7 @@ static int stm32mp1_clk_probe(struct udevice *dev)
log_info("- DDR : %s MHz\n", strmhz(buf, gd->mem_clk));
}
}
+#endif
return 0;
}
diff --git a/drivers/clk/stm32/clk-stm32mp25.c b/drivers/clk/stm32/clk-stm32mp25.c
new file mode 100644
index 00000000000..18c0b1cb867
--- /dev/null
+++ b/drivers/clk/stm32/clk-stm32mp25.c
@@ -0,0 +1,782 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause
+/*
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ */
+
+#include <clk-uclass.h>
+#include <dm.h>
+#include <dt-bindings/clock/st,stm32mp25-rcc.h>
+#include <linux/bitfield.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <mach/rif.h>
+
+#include "clk-stm32-core.h"
+#include "stm32mp25_rcc.h"
+
+/* Clock security definition */
+#define SECF_NONE -1
+
+#define RCC_REG_SIZE 32
+#define RCC_SECCFGR(x) (((x) / RCC_REG_SIZE) * 0x4 + RCC_SECCFGR0)
+#define RCC_CIDCFGR(x) ((x) * 0x8 + RCC_R0CIDCFGR)
+#define RCC_SEMCR(x) ((x) * 0x8 + RCC_R0SEMCR)
+#define RCC_CID1 1
+
+/* Register: RIFSC_CIDCFGR */
+#define RCC_CIDCFGR_CFEN BIT(0)
+#define RCC_CIDCFGR_SEM_EN BIT(1)
+#define RCC_CIDCFGR_SEMWLC1_EN BIT(17)
+#define RCC_CIDCFGR_SCID_MASK GENMASK(6, 4)
+
+/* Register: RIFSC_SEMCR */
+#define RCC_SEMCR_SEMCID_MASK GENMASK(6, 4)
+
+#define STM32MP25_RIFRCC_DBG_ID 73
+#define STM32MP25_RIFRCC_IS2M_ID 107
+#define STM32MP25_RIFRCC_MCO1_ID 108
+#define STM32MP25_RIFRCC_MCO2_ID 109
+#define STM32MP25_RIFRCC_OSPI1_ID 110
+#define STM32MP25_RIFRCC_OSPI2_ID 111
+
+#define SEC_RIFSC_FLAG BIT(31)
+#define SEC_RIFRCC(_id) (STM32MP25_RIFRCC_##_id##_ID)
+#define SEC_RIFSC(_id) ((_id) | SEC_RIFSC_FLAG)
+
+static const char * const adc12_src[] = {
+ "ck_flexgen_46", "ck_icn_ls_mcu"
+};
+
+static const char * const adc3_src[] = {
+ "ck_flexgen_47", "ck_icn_ls_mcu", "ck_flexgen_46"
+};
+
+static const char * const usb2phy1_src[] = {
+ "ck_flexgen_57", "hse_div2_ck"
+};
+
+static const char * const usb2phy2_src[] = {
+ "ck_flexgen_58", "hse_div2_ck"
+};
+
+static const char * const usb3pciphy_src[] = {
+ "ck_flexgen_34", "hse_div2_ck"
+};
+
+static const char * const dsiblane_src[] = {
+ "txbyteclk", "ck_ker_ltdc"
+};
+
+static const char * const dsiphy_src[] = {
+ "ck_flexgen_28", "hse_ck"
+};
+
+static const char * const lvdsphy_src[] = {
+ "ck_flexgen_32", "hse_ck"
+};
+
+static const char * const dts_src[] = {
+ "hsi_ck", "hse_ck", "msi_ck"
+};
+
+static const char * const mco1_src[] = {
+ "ck_flexgen_61", "ck_obs0"
+};
+
+static const char * const mco2_src[] = {
+ "ck_flexgen_62", "ck_obs1"
+};
+
+enum enum_mux_cfg {
+ MUX_MCO1,
+ MUX_MCO2,
+ MUX_ADC12,
+ MUX_ADC3,
+ MUX_USB2PHY1,
+ MUX_USB2PHY2,
+ MUX_USB3PCIEPHY,
+ MUX_DSIBLANE,
+ MUX_DSIPHY,
+ MUX_LVDSPHY,
+ MUX_DTS,
+ MUX_NB
+};
+
+#define MUX_CFG(id, src, _offset, _shift, _witdh)[id] = {\
+ .num_parents = ARRAY_SIZE(src),\
+ .parent_names = src,\
+ .reg_off = (_offset),\
+ .shift = (_shift),\
+ .width = (_witdh),\
+}
+
+static const struct stm32_mux_cfg stm32mp25_muxes[MUX_NB] = {
+ MUX_CFG(MUX_ADC12, adc12_src, RCC_ADC12CFGR, 12, 1),
+ MUX_CFG(MUX_ADC3, adc3_src, RCC_ADC3CFGR, 12, 2),
+ MUX_CFG(MUX_DSIBLANE, dsiblane_src, RCC_DSICFGR, 12, 1),
+ MUX_CFG(MUX_DSIPHY, dsiphy_src, RCC_DSICFGR, 15, 1),
+ MUX_CFG(MUX_DTS, dts_src, RCC_DTSCFGR, 12, 2),
+ MUX_CFG(MUX_MCO1, mco1_src, RCC_MCO1CFGR, 0, 1),
+ MUX_CFG(MUX_MCO2, mco2_src, RCC_MCO2CFGR, 0, 1),
+ MUX_CFG(MUX_LVDSPHY, lvdsphy_src, RCC_LVDSCFGR, 15, 1),
+ MUX_CFG(MUX_USB2PHY1, usb2phy1_src, RCC_USB2PHY1CFGR, 15, 1),
+ MUX_CFG(MUX_USB2PHY2, usb2phy2_src, RCC_USB2PHY2CFGR, 15, 1),
+ MUX_CFG(MUX_USB3PCIEPHY, usb3pciphy_src, RCC_USB3PCIEPHYCFGR, 15, 1),
+};
+
+enum enum_gate_cfg {
+ GATE_ADC12,
+ GATE_ADC3,
+ GATE_ADF1,
+ GATE_CCI,
+ GATE_CRC,
+ GATE_CRYP1,
+ GATE_CRYP2,
+ GATE_CSI,
+ GATE_DBG,
+ GATE_DCMIPP,
+ GATE_DSI,
+ GATE_DTS,
+ GATE_ETH1,
+ GATE_ETH1MAC,
+ GATE_ETH1RX,
+ GATE_ETH1STP,
+ GATE_ETH1TX,
+ GATE_ETH2,
+ GATE_ETH2MAC,
+ GATE_ETH2RX,
+ GATE_ETH2STP,
+ GATE_ETH2TX,
+ GATE_ETHSW,
+ GATE_ETHSWMAC,
+ GATE_ETHSWREF,
+ GATE_ETR,
+ GATE_FDCAN,
+ GATE_GPU,
+ GATE_HASH,
+ GATE_HDP,
+ GATE_I2C1,
+ GATE_I2C2,
+ GATE_I2C3,
+ GATE_I2C4,
+ GATE_I2C5,
+ GATE_I2C6,
+ GATE_I2C7,
+ GATE_I2C8,
+ GATE_I3C1,
+ GATE_I3C2,
+ GATE_I3C3,
+ GATE_I3C4,
+ GATE_IS2M,
+ GATE_IWDG1,
+ GATE_IWDG2,
+ GATE_IWDG3,
+ GATE_IWDG4,
+ GATE_IWDG5,
+ GATE_LPTIM1,
+ GATE_LPTIM2,
+ GATE_LPTIM3,
+ GATE_LPTIM4,
+ GATE_LPTIM5,
+ GATE_LPUART1,
+ GATE_LTDC,
+ GATE_LVDS,
+ GATE_MCO1,
+ GATE_MCO2,
+ GATE_MDF1,
+ GATE_OSPI1,
+ GATE_OSPI2,
+ GATE_OSPIIOM,
+ GATE_PCIE,
+ GATE_PKA,
+ GATE_RNG,
+ GATE_SAES,
+ GATE_SAI1,
+ GATE_SAI2,
+ GATE_SAI3,
+ GATE_SAI4,
+ GATE_SDMMC1,
+ GATE_SDMMC2,
+ GATE_SDMMC3,
+ GATE_SERC,
+ GATE_SPDIFRX,
+ GATE_SPI1,
+ GATE_SPI2,
+ GATE_SPI3,
+ GATE_SPI4,
+ GATE_SPI5,
+ GATE_SPI6,
+ GATE_SPI7,
+ GATE_SPI8,
+ GATE_STGEN,
+ GATE_STM500,
+ GATE_TIM1,
+ GATE_TIM2,
+ GATE_TIM3,
+ GATE_TIM4,
+ GATE_TIM5,
+ GATE_TIM6,
+ GATE_TIM7,
+ GATE_TIM8,
+ GATE_TIM10,
+ GATE_TIM11,
+ GATE_TIM12,
+ GATE_TIM13,
+ GATE_TIM14,
+ GATE_TIM15,
+ GATE_TIM16,
+ GATE_TIM17,
+ GATE_TIM20,
+ GATE_TRACE,
+ GATE_UART4,
+ GATE_UART5,
+ GATE_UART7,
+ GATE_UART8,
+ GATE_UART9,
+ GATE_USART1,
+ GATE_USART2,
+ GATE_USART3,
+ GATE_USART6,
+ GATE_USBH,
+ GATE_USB2PHY1,
+ GATE_USB2PHY2,
+ GATE_USB3DR,
+ GATE_USB3PCIEPHY,
+ GATE_USBTC,
+ GATE_VDEC,
+ GATE_VENC,
+ GATE_VREF,
+ GATE_WWDG1,
+ GATE_WWDG2,
+ GATE_NB
+};
+
+#define GATE_CFG(id, _offset, _bit_idx, _offset_clr)[id] = {\
+ .reg_off = (_offset),\
+ .bit_idx = (_bit_idx),\
+ .set_clr = (_offset_clr),\
+}
+
+static const struct stm32_gate_cfg stm32mp25_gates[GATE_NB] = {
+ GATE_CFG(GATE_MCO1, RCC_MCO1CFGR, 8, 0),
+ GATE_CFG(GATE_MCO2, RCC_MCO2CFGR, 8, 0),
+ GATE_CFG(GATE_OSPI1, RCC_OSPI1CFGR, 1, 0),
+ GATE_CFG(GATE_OSPI2, RCC_OSPI2CFGR, 1, 0),
+ GATE_CFG(GATE_DBG, RCC_DBGCFGR, 8, 0),
+ GATE_CFG(GATE_TRACE, RCC_DBGCFGR, 9, 0),
+ GATE_CFG(GATE_STM500, RCC_STM500CFGR, 1, 0),
+ GATE_CFG(GATE_ETR, RCC_ETRCFGR, 1, 0),
+ GATE_CFG(GATE_IS2M, RCC_IS2MCFGR, 1, 0),
+ GATE_CFG(GATE_TIM1, RCC_TIM1CFGR, 1, 0),
+ GATE_CFG(GATE_TIM2, RCC_TIM2CFGR, 1, 0),
+ GATE_CFG(GATE_TIM3, RCC_TIM3CFGR, 1, 0),
+ GATE_CFG(GATE_TIM4, RCC_TIM4CFGR, 1, 0),
+ GATE_CFG(GATE_TIM5, RCC_TIM5CFGR, 1, 0),
+ GATE_CFG(GATE_TIM6, RCC_TIM6CFGR, 1, 0),
+ GATE_CFG(GATE_TIM7, RCC_TIM7CFGR, 1, 0),
+ GATE_CFG(GATE_TIM8, RCC_TIM8CFGR, 1, 0),
+ GATE_CFG(GATE_TIM10, RCC_TIM10CFGR, 1, 0),
+ GATE_CFG(GATE_TIM11, RCC_TIM11CFGR, 1, 0),
+ GATE_CFG(GATE_TIM12, RCC_TIM12CFGR, 1, 0),
+ GATE_CFG(GATE_TIM13, RCC_TIM13CFGR, 1, 0),
+ GATE_CFG(GATE_TIM14, RCC_TIM14CFGR, 1, 0),
+ GATE_CFG(GATE_TIM15, RCC_TIM15CFGR, 1, 0),
+ GATE_CFG(GATE_TIM16, RCC_TIM16CFGR, 1, 0),
+ GATE_CFG(GATE_TIM17, RCC_TIM17CFGR, 1, 0),
+ GATE_CFG(GATE_TIM20, RCC_TIM20CFGR, 1, 0),
+ GATE_CFG(GATE_LPTIM1, RCC_LPTIM1CFGR, 1, 0),
+ GATE_CFG(GATE_LPTIM2, RCC_LPTIM2CFGR, 1, 0),
+ GATE_CFG(GATE_LPTIM3, RCC_LPTIM3CFGR, 1, 0),
+ GATE_CFG(GATE_LPTIM4, RCC_LPTIM4CFGR, 1, 0),
+ GATE_CFG(GATE_LPTIM5, RCC_LPTIM5CFGR, 1, 0),
+ GATE_CFG(GATE_SPI1, RCC_SPI1CFGR, 1, 0),
+ GATE_CFG(GATE_SPI2, RCC_SPI2CFGR, 1, 0),
+ GATE_CFG(GATE_SPI3, RCC_SPI3CFGR, 1, 0),
+ GATE_CFG(GATE_SPI4, RCC_SPI4CFGR, 1, 0),
+ GATE_CFG(GATE_SPI5, RCC_SPI5CFGR, 1, 0),
+ GATE_CFG(GATE_SPI6, RCC_SPI6CFGR, 1, 0),
+ GATE_CFG(GATE_SPI7, RCC_SPI7CFGR, 1, 0),
+ GATE_CFG(GATE_SPI8, RCC_SPI8CFGR, 1, 0),
+ GATE_CFG(GATE_SPDIFRX, RCC_SPDIFRXCFGR, 1, 0),
+ GATE_CFG(GATE_USART1, RCC_USART1CFGR, 1, 0),
+ GATE_CFG(GATE_USART2, RCC_USART2CFGR, 1, 0),
+ GATE_CFG(GATE_USART3, RCC_USART3CFGR, 1, 0),
+ GATE_CFG(GATE_UART4, RCC_UART4CFGR, 1, 0),
+ GATE_CFG(GATE_UART5, RCC_UART5CFGR, 1, 0),
+ GATE_CFG(GATE_USART6, RCC_USART6CFGR, 1, 0),
+ GATE_CFG(GATE_UART7, RCC_UART7CFGR, 1, 0),
+ GATE_CFG(GATE_UART8, RCC_UART8CFGR, 1, 0),
+ GATE_CFG(GATE_UART9, RCC_UART9CFGR, 1, 0),
+ GATE_CFG(GATE_LPUART1, RCC_LPUART1CFGR, 1, 0),
+ GATE_CFG(GATE_I2C1, RCC_I2C1CFGR, 1, 0),
+ GATE_CFG(GATE_I2C2, RCC_I2C2CFGR, 1, 0),
+ GATE_CFG(GATE_I2C3, RCC_I2C3CFGR, 1, 0),
+ GATE_CFG(GATE_I2C4, RCC_I2C4CFGR, 1, 0),
+ GATE_CFG(GATE_I2C5, RCC_I2C5CFGR, 1, 0),
+ GATE_CFG(GATE_I2C6, RCC_I2C6CFGR, 1, 0),
+ GATE_CFG(GATE_I2C7, RCC_I2C7CFGR, 1, 0),
+ GATE_CFG(GATE_I2C8, RCC_I2C8CFGR, 1, 0),
+ GATE_CFG(GATE_SAI1, RCC_SAI1CFGR, 1, 0),
+ GATE_CFG(GATE_SAI2, RCC_SAI2CFGR, 1, 0),
+ GATE_CFG(GATE_SAI3, RCC_SAI3CFGR, 1, 0),
+ GATE_CFG(GATE_SAI4, RCC_SAI4CFGR, 1, 0),
+ GATE_CFG(GATE_MDF1, RCC_MDF1CFGR, 1, 0),
+ GATE_CFG(GATE_ADF1, RCC_ADF1CFGR, 1, 0),
+ GATE_CFG(GATE_FDCAN, RCC_FDCANCFGR, 1, 0),
+ GATE_CFG(GATE_HDP, RCC_HDPCFGR, 1, 0),
+ GATE_CFG(GATE_ADC12, RCC_ADC12CFGR, 1, 0),
+ GATE_CFG(GATE_ADC3, RCC_ADC3CFGR, 1, 0),
+ GATE_CFG(GATE_ETH1MAC, RCC_ETH1CFGR, 1, 0),
+ GATE_CFG(GATE_ETH1STP, RCC_ETH1CFGR, 4, 0),
+ GATE_CFG(GATE_ETH1, RCC_ETH1CFGR, 5, 0),
+ GATE_CFG(GATE_ETH1TX, RCC_ETH1CFGR, 8, 0),
+ GATE_CFG(GATE_ETH1RX, RCC_ETH1CFGR, 10, 0),
+ GATE_CFG(GATE_ETH2MAC, RCC_ETH2CFGR, 1, 0),
+ GATE_CFG(GATE_ETH2STP, RCC_ETH2CFGR, 4, 0),
+ GATE_CFG(GATE_ETH2, RCC_ETH2CFGR, 5, 0),
+ GATE_CFG(GATE_ETH2TX, RCC_ETH2CFGR, 8, 0),
+ GATE_CFG(GATE_ETH2RX, RCC_ETH2CFGR, 10, 0),
+ GATE_CFG(GATE_USBH, RCC_USBHCFGR, 1, 0),
+ GATE_CFG(GATE_USB2PHY1, RCC_USB2PHY1CFGR, 1, 0),
+ GATE_CFG(GATE_USB2PHY2, RCC_USB2PHY2CFGR, 1, 0),
+ GATE_CFG(GATE_USB3DR, RCC_USB3DRCFGR, 1, 0),
+ GATE_CFG(GATE_USB3PCIEPHY, RCC_USB3PCIEPHYCFGR, 1, 0),
+ GATE_CFG(GATE_PCIE, RCC_PCIECFGR, 1, 0),
+ GATE_CFG(GATE_USBTC, RCC_UCPDCFGR, 1, 0),
+ GATE_CFG(GATE_ETHSWMAC, RCC_ETHSWCFGR, 1, 0),
+ GATE_CFG(GATE_ETHSW, RCC_ETHSWCFGR, 5, 0),
+ GATE_CFG(GATE_ETHSWREF, RCC_ETHSWCFGR, 21, 0),
+ GATE_CFG(GATE_STGEN, RCC_STGENCFGR, 1, 0),
+ GATE_CFG(GATE_SDMMC1, RCC_SDMMC1CFGR, 1, 0),
+ GATE_CFG(GATE_SDMMC2, RCC_SDMMC2CFGR, 1, 0),
+ GATE_CFG(GATE_SDMMC3, RCC_SDMMC3CFGR, 1, 0),
+ GATE_CFG(GATE_GPU, RCC_GPUCFGR, 1, 0),
+ GATE_CFG(GATE_LTDC, RCC_LTDCCFGR, 1, 0),
+ GATE_CFG(GATE_DSI, RCC_DSICFGR, 1, 0),
+ GATE_CFG(GATE_LVDS, RCC_LVDSCFGR, 1, 0),
+ GATE_CFG(GATE_CSI, RCC_CSICFGR, 1, 0),
+ GATE_CFG(GATE_DCMIPP, RCC_DCMIPPCFGR, 1, 0),
+ GATE_CFG(GATE_CCI, RCC_CCICFGR, 1, 0),
+ GATE_CFG(GATE_VDEC, RCC_VDECCFGR, 1, 0),
+ GATE_CFG(GATE_VENC, RCC_VENCCFGR, 1, 0),
+ GATE_CFG(GATE_RNG, RCC_RNGCFGR, 1, 0),
+ GATE_CFG(GATE_PKA, RCC_PKACFGR, 1, 0),
+ GATE_CFG(GATE_SAES, RCC_SAESCFGR, 1, 0),
+ GATE_CFG(GATE_HASH, RCC_HASHCFGR, 1, 0),
+ GATE_CFG(GATE_CRYP1, RCC_CRYP1CFGR, 1, 0),
+ GATE_CFG(GATE_CRYP2, RCC_CRYP2CFGR, 1, 0),
+ GATE_CFG(GATE_IWDG1, RCC_IWDG1CFGR, 1, 0),
+ GATE_CFG(GATE_IWDG2, RCC_IWDG2CFGR, 1, 0),
+ GATE_CFG(GATE_IWDG3, RCC_IWDG3CFGR, 1, 0),
+ GATE_CFG(GATE_IWDG4, RCC_IWDG4CFGR, 1, 0),
+ GATE_CFG(GATE_IWDG5, RCC_IWDG5CFGR, 1, 0),
+ GATE_CFG(GATE_WWDG1, RCC_WWDG1CFGR, 1, 0),
+ GATE_CFG(GATE_WWDG2, RCC_WWDG2CFGR, 1, 0),
+ GATE_CFG(GATE_VREF, RCC_VREFCFGR, 1, 0),
+ GATE_CFG(GATE_DTS, RCC_DTSCFGR, 1, 0),
+ GATE_CFG(GATE_CRC, RCC_CRCCFGR, 1, 0),
+ GATE_CFG(GATE_SERC, RCC_SERCCFGR, 1, 0),
+ GATE_CFG(GATE_OSPIIOM, RCC_OSPIIOMCFGR, 1, 0),
+ GATE_CFG(GATE_I3C1, RCC_I3C1CFGR, 1, 0),
+ GATE_CFG(GATE_I3C2, RCC_I3C2CFGR, 1, 0),
+ GATE_CFG(GATE_I3C3, RCC_I3C3CFGR, 1, 0),
+ GATE_CFG(GATE_I3C4, RCC_I3C4CFGR, 1, 0),
+};
+
+static int stm32_rcc_get_access(struct udevice *dev, u32 index)
+{
+ fdt_addr_t rcc_base = dev_read_addr(dev->parent);
+ u32 seccfgr, cidcfgr, semcr;
+ int bit, cid;
+
+ bit = index % RCC_REG_SIZE;
+
+ seccfgr = readl(rcc_base + RCC_SECCFGR(index));
+ if (seccfgr & BIT(bit))
+ return -EACCES;
+
+ cidcfgr = readl(rcc_base + RCC_CIDCFGR(index));
+ if (!(cidcfgr & RCC_CIDCFGR_CFEN))
+ /* CID filtering is turned off: access granted */
+ return 0;
+
+ if (!(cidcfgr & RCC_CIDCFGR_SEM_EN)) {
+ /* Static CID mode */
+ cid = FIELD_GET(RCC_CIDCFGR_SCID_MASK, cidcfgr);
+ if (cid != RCC_CID1)
+ return -EACCES;
+ return 0;
+ }
+
+ /* Pass-list with semaphore mode */
+ if (!(cidcfgr & RCC_CIDCFGR_SEMWLC1_EN))
+ return -EACCES;
+
+ semcr = readl(rcc_base + RCC_SEMCR(index));
+
+ cid = FIELD_GET(RCC_SEMCR_SEMCID_MASK, semcr);
+ if (cid != RCC_CID1)
+ return -EACCES;
+
+ return 0;
+}
+
+static int stm32mp25_check_security(struct udevice *dev, void __iomem *base,
+ const struct clock_config *cfg)
+{
+ int ret = 0;
+
+ if (cfg->sec_id != SECF_NONE) {
+ u32 index = (u32)cfg->sec_id;
+
+ if (index & SEC_RIFSC_FLAG)
+ ret = stm32_rifsc_check_access_by_id(dev_ofnode(dev),
+ index & ~SEC_RIFSC_FLAG);
+ else
+ ret = stm32_rcc_get_access(dev, index);
+ }
+
+ return ret;
+}
+#define STM32_COMPOSITE_NODIV(_id, _name, _flags, _sec_id, _gate_id, _mux_id)\
+ STM32_COMPOSITE(_id, _name, _flags, _sec_id, _gate_id, _mux_id, NO_STM32_DIV)
+
+static const struct clock_config stm32mp25_clock_cfg[] = {
+ /* ADC */
+ STM32_GATE(CK_BUS_ADC12, "ck_icn_p_adc12", "ck_icn_ls_mcu", 0, GATE_ADC12,
+ SEC_RIFSC(58)),
+ STM32_COMPOSITE_NODIV(CK_KER_ADC12, "ck_ker_adc12", 0, SEC_RIFSC(58),
+ GATE_ADC12, MUX_ADC12),
+ STM32_GATE(CK_BUS_ADC3, "ck_icn_p_adc3", "ck_icn_ls_mcu", 0, GATE_ADC3, SEC_RIFSC(59)),
+ STM32_COMPOSITE_NODIV(CK_KER_ADC3, "ck_ker_adc3", 0, SEC_RIFSC(59), GATE_ADC3, MUX_ADC3),
+
+ /* ADF */
+ STM32_GATE(CK_BUS_ADF1, "ck_icn_p_adf1", "ck_icn_ls_mcu", 0, GATE_ADF1, SEC_RIFSC(55)),
+ STM32_GATE(CK_KER_ADF1, "ck_ker_adf1", "ck_flexgen_42", 0, GATE_ADF1, SEC_RIFSC(55)),
+
+ /* Camera */
+ /* DCMI */
+ STM32_GATE(CK_BUS_CCI, "ck_icn_p_cci", "ck_icn_ls_mcu", 0, GATE_CCI, SEC_RIFSC(88)),
+
+ /* CSI-HOST */
+ STM32_GATE(CK_BUS_CSI, "ck_icn_p_csi", "ck_icn_apb4", 0, GATE_CSI, SEC_RIFSC(86)),
+ STM32_GATE(CK_KER_CSI, "ck_ker_csi", "ck_flexgen_29", 0, GATE_CSI, SEC_RIFSC(86)),
+ STM32_GATE(CK_KER_CSITXESC, "ck_ker_csitxesc", "ck_flexgen_30", 0, GATE_CSI,
+ SEC_RIFSC(86)),
+
+ /* CSI-PHY */
+ STM32_GATE(CK_KER_CSIPHY, "ck_ker_csiphy", "ck_flexgen_31", 0, GATE_CSI,
+ SEC_RIFSC(86)),
+
+ /* DCMIPP */
+ STM32_GATE(CK_BUS_DCMIPP, "ck_icn_p_dcmipp", "ck_icn_apb4", 0, GATE_DCMIPP,
+ SEC_RIFSC(87)),
+
+ /* CRC */
+ STM32_GATE(CK_BUS_CRC, "ck_icn_p_crc", "ck_icn_ls_mcu", 0, GATE_CRC, SEC_RIFSC(109)),
+
+ /* CRYP */
+ STM32_GATE(CK_BUS_CRYP1, "ck_icn_p_cryp1", "ck_icn_ls_mcu", 0, GATE_CRYP1,
+ SEC_RIFSC(96)),
+ STM32_GATE(CK_BUS_CRYP2, "ck_icn_p_cryp2", "ck_icn_ls_mcu", 0, GATE_CRYP2,
+ SEC_RIFSC(97)),
+
+ /* DBG & TRACE*/
+ /* Trace and debug clocks are managed by SCMI */
+
+ /* Display subsystem */
+ /* LTDC */
+ STM32_GATE(CK_BUS_LTDC, "ck_icn_p_ltdc", "ck_icn_apb4", 0, GATE_LTDC, SEC_RIFSC(80)),
+ STM32_GATE(CK_KER_LTDC, "ck_ker_ltdc", "ck_flexgen_27", CLK_SET_RATE_PARENT, GATE_LTDC,
+ SEC_RIFSC(80)),
+
+ /* DSI */
+ STM32_GATE(CK_BUS_DSI, "ck_icn_p_dsi", "ck_icn_apb4", 0, GATE_DSI, SEC_RIFSC(81)),
+ STM32_COMPOSITE_NODIV(CK_KER_DSIBLANE, "clk_lanebyte", 0, SEC_RIFSC(81),
+ GATE_DSI, MUX_DSIBLANE),
+
+ /* LVDS */
+ STM32_GATE(CK_BUS_LVDS, "ck_icn_p_lvds", "ck_icn_apb4", 0, GATE_LVDS, SEC_RIFSC(84)),
+
+ /* DSI PHY */
+ STM32_COMPOSITE_NODIV(CK_KER_DSIPHY, "ck_ker_dsiphy", 0, SEC_RIFSC(81),
+ GATE_DSI, MUX_DSIPHY),
+
+ /* LVDS PHY */
+ STM32_COMPOSITE_NODIV(CK_KER_LVDSPHY, "ck_ker_lvdsphy", 0, SEC_RIFSC(84),
+ GATE_LVDS, MUX_LVDSPHY),
+
+ /* DTS */
+ STM32_COMPOSITE_NODIV(CK_KER_DTS, "ck_ker_dts", 0, SEC_RIFSC(107), GATE_DTS, MUX_DTS),
+
+ /* ETHERNET */
+ STM32_GATE(CK_BUS_ETH1, "ck_icn_p_eth1", "ck_icn_ls_mcu", 0, GATE_ETH1, SEC_RIFSC(60)),
+ STM32_GATE(CK_ETH1_STP, "ck_ker_eth1stp", "ck_icn_ls_mcu", 0, GATE_ETH1STP,
+ SEC_RIFSC(60)),
+ STM32_GATE(CK_KER_ETH1, "ck_ker_eth1", "ck_flexgen_54", 0, GATE_ETH1, SEC_RIFSC(60)),
+ STM32_GATE(CK_KER_ETH1, "ck_ker_eth1ptp", "ck_flexgen_56", 0, GATE_ETH1, SEC_RIFSC(60)),
+ STM32_GATE(CK_ETH1_MAC, "ck_ker_eth1mac", "ck_icn_ls_mcu", 0, GATE_ETH1MAC,
+ SEC_RIFSC(60)),
+ STM32_GATE(CK_ETH1_TX, "ck_ker_eth1tx", "ck_icn_ls_mcu", 0, GATE_ETH1TX, SEC_RIFSC(60)),
+ STM32_GATE(CK_ETH1_RX, "ck_ker_eth1rx", "ck_icn_ls_mcu", 0, GATE_ETH1RX, SEC_RIFSC(60)),
+
+ STM32_GATE(CK_BUS_ETH2, "ck_icn_p_eth2", "ck_icn_ls_mcu", 0, GATE_ETH2, SEC_RIFSC(61)),
+ STM32_GATE(CK_ETH2_STP, "ck_ker_eth2stp", "ck_icn_ls_mcu", 0, GATE_ETH2STP,
+ SEC_RIFSC(61)),
+ STM32_GATE(CK_KER_ETH2, "ck_ker_eth2", "ck_flexgen_54", 0, GATE_ETH2, SEC_RIFSC(61)),
+ STM32_GATE(CK_KER_ETH2, "ck_ker_eth2ptp", "ck_flexgen_56", 0, GATE_ETH2, SEC_RIFSC(61)),
+ STM32_GATE(CK_ETH2_MAC, "ck_ker_eth2mac", "ck_icn_ls_mcu", 0, GATE_ETH2MAC,
+ SEC_RIFSC(61)),
+ STM32_GATE(CK_ETH2_TX, "ck_ker_eth2tx", "ck_icn_ls_mcu", 0, GATE_ETH2TX, SEC_RIFSC(61)),
+ STM32_GATE(CK_ETH2_RX, "ck_ker_eth2rx", "ck_icn_ls_mcu", 0, GATE_ETH2RX, SEC_RIFSC(61)),
+
+ STM32_GATE(CK_BUS_ETHSW, "ck_icn_p_ethsw", "ck_icn_ls_mcu", 0, GATE_ETHSWMAC,
+ SEC_RIFSC(70)),
+ STM32_GATE(CK_KER_ETHSW, "ck_ker_ethsw", "ck_flexgen_54", 0, GATE_ETHSW,
+ SEC_RIFSC(70)),
+ STM32_GATE(CK_KER_ETHSWREF, "ck_ker_ethswref", "ck_flexgen_60", 0, GATE_ETHSWREF,
+ SEC_RIFSC(70)),
+
+ /* FDCAN */
+ STM32_GATE(CK_BUS_FDCAN, "ck_icn_p_fdcan", "ck_icn_apb2", 0, GATE_FDCAN, SEC_RIFSC(56)),
+ STM32_GATE(CK_KER_FDCAN, "ck_ker_fdcan", "ck_flexgen_26", 0, GATE_FDCAN, SEC_RIFSC(56)),
+
+ /* GPU */
+ STM32_GATE(CK_BUS_GPU, "ck_icn_m_gpu", "ck_flexgen_59", 0, GATE_GPU, SEC_RIFSC(79)),
+ STM32_GATE(CK_KER_GPU, "ck_ker_gpu", "ck_pll3", 0, GATE_GPU, SEC_RIFSC(79)),
+
+ /* HASH */
+ STM32_GATE(CK_BUS_HASH, "ck_icn_p_hash", "ck_icn_ls_mcu", 0, GATE_HASH, SEC_RIFSC(95)),
+
+ /* HDP */
+ STM32_GATE(CK_BUS_HDP, "ck_icn_p_hdp", "ck_icn_apb3", 0, GATE_HDP, SEC_RIFSC(57)),
+
+ /* I2C */
+ STM32_GATE(CK_KER_I2C1, "ck_ker_i2c1", "ck_flexgen_12", 0, GATE_I2C1, SEC_RIFSC(41)),
+ STM32_GATE(CK_KER_I2C2, "ck_ker_i2c2", "ck_flexgen_12", 0, GATE_I2C2, SEC_RIFSC(42)),
+ STM32_GATE(CK_KER_I2C3, "ck_ker_i2c3", "ck_flexgen_13", 0, GATE_I2C3, SEC_RIFSC(43)),
+ STM32_GATE(CK_KER_I2C5, "ck_ker_i2c5", "ck_flexgen_13", 0, GATE_I2C5, SEC_RIFSC(45)),
+ STM32_GATE(CK_KER_I2C4, "ck_ker_i2c4", "ck_flexgen_14", 0, GATE_I2C4, SEC_RIFSC(44)),
+ STM32_GATE(CK_KER_I2C6, "ck_ker_i2c6", "ck_flexgen_14", 0, GATE_I2C6, SEC_RIFSC(46)),
+ STM32_GATE(CK_KER_I2C7, "ck_ker_i2c7", "ck_flexgen_15", 0, GATE_I2C7, SEC_RIFSC(47)),
+ STM32_GATE(CK_KER_I2C8, "ck_ker_i2c8", "ck_flexgen_38", 0, GATE_I2C8, SEC_RIFSC(48)),
+
+ /* I3C */
+ STM32_GATE(CK_KER_I3C1, "ck_ker_i3c1", "ck_flexgen_12", 0, GATE_I3C1, SEC_RIFSC(114)),
+ STM32_GATE(CK_KER_I3C2, "ck_ker_i3c2", "ck_flexgen_12", 0, GATE_I3C2, SEC_RIFSC(115)),
+ STM32_GATE(CK_KER_I3C3, "ck_ker_i3c3", "ck_flexgen_13", 0, GATE_I3C3, SEC_RIFSC(116)),
+ STM32_GATE(CK_KER_I3C4, "ck_ker_i3c4", "ck_flexgen_36", 0, GATE_I3C4, SEC_RIFSC(117)),
+
+ /* I2S */
+ STM32_GATE(CK_BUS_IS2M, "ck_icn_p_is2m", "ck_icn_apb3", 0, GATE_IS2M, SEC_RIFRCC(IS2M)),
+
+ /* IWDG */
+ STM32_GATE(CK_BUS_IWDG1, "ck_icn_p_iwdg1", "ck_icn_apb3", 0, GATE_IWDG1, SEC_RIFSC(98)),
+ STM32_GATE(CK_BUS_IWDG2, "ck_icn_p_iwdg2", "ck_icn_apb3", 0, GATE_IWDG2, SEC_RIFSC(99)),
+ STM32_GATE(CK_BUS_IWDG3, "ck_icn_p_iwdg3", "ck_icn_apb3", 0, GATE_IWDG3, SEC_RIFSC(100)),
+ STM32_GATE(CK_BUS_IWDG4, "ck_icn_p_iwdg4", "ck_icn_apb3", 0, GATE_IWDG4, SEC_RIFSC(101)),
+ STM32_GATE(CK_BUS_IWDG5, "ck_icn_p_iwdg5", "ck_icn_ls_mcu", 0, GATE_IWDG5,
+ SEC_RIFSC(102)),
+
+ /* LPTIM */
+ STM32_GATE(CK_KER_LPTIM1, "ck_ker_lptim1", "ck_flexgen_07", 0, GATE_LPTIM1,
+ SEC_RIFSC(17)),
+ STM32_GATE(CK_KER_LPTIM2, "ck_ker_lptim2", "ck_flexgen_07", 0, GATE_LPTIM2,
+ SEC_RIFSC(18)),
+ STM32_GATE(CK_KER_LPTIM3, "ck_ker_lptim3", "ck_flexgen_40", 0, GATE_LPTIM3,
+ SEC_RIFSC(19)),
+ STM32_GATE(CK_KER_LPTIM4, "ck_ker_lptim4", "ck_flexgen_41", 0, GATE_LPTIM4,
+ SEC_RIFSC(20)),
+ STM32_GATE(CK_KER_LPTIM5, "ck_ker_lptim5", "ck_flexgen_41", 0, GATE_LPTIM5,
+ SEC_RIFSC(21)),
+
+ /* LPUART */
+ STM32_GATE(CK_KER_LPUART1, "ck_ker_lpuart1", "ck_flexgen_39", 0, GATE_LPUART1,
+ SEC_RIFSC(40)),
+
+ /* MCO1 & MCO2 */
+ STM32_COMPOSITE_NODIV(CK_MCO1, "ck_mco1", 0, SEC_RIFRCC(MCO1), GATE_MCO1, MUX_MCO1),
+ STM32_COMPOSITE_NODIV(CK_MCO2, "ck_mco2", 0, SEC_RIFRCC(MCO2), GATE_MCO2, MUX_MCO2),
+
+ /* MDF */
+ STM32_GATE(CK_KER_MDF1, "ck_ker_mdf1", "ck_flexgen_23", 0, GATE_MDF1, SEC_RIFSC(54)),
+
+ /* OCTOSPI */
+ STM32_GATE(CK_BUS_OSPIIOM, "ck_icn_p_ospiiom", "ck_icn_ls_mcu", 0, GATE_OSPIIOM,
+ SEC_RIFSC(111)),
+
+ /* PCIE */
+ STM32_GATE(CK_BUS_PCIE, "ck_icn_p_pcie", "ck_icn_ls_mcu", 0, GATE_PCIE, SEC_RIFSC(68)),
+
+ /* PKA */
+ STM32_GATE(CK_BUS_PKA, "ck_icn_p_pka", "ck_icn_ls_mcu", 0, GATE_PKA, SEC_RIFSC(93)),
+
+ /* RNG */
+ STM32_GATE(CK_BUS_RNG, "ck_icn_p_rng", "ck_icn_ls_mcu", CLK_IGNORE_UNUSED, GATE_RNG,
+ SEC_RIFSC(92)),
+
+ /* SAES */
+ STM32_GATE(CK_BUS_SAES, "ck_icn_p_saes", "ck_icn_ls_mcu", 0, GATE_SAES, SEC_RIFSC(94)),
+
+ /* SAI [1..4] */
+ STM32_GATE(CK_BUS_SAI1, "ck_icn_p_sai1", "ck_icn_apb2", 0, GATE_SAI1, SEC_RIFSC(49)),
+ STM32_GATE(CK_BUS_SAI2, "ck_icn_p_sai2", "ck_icn_apb2", 0, GATE_SAI2, SEC_RIFSC(50)),
+ STM32_GATE(CK_BUS_SAI3, "ck_icn_p_sai3", "ck_icn_apb2", 0, GATE_SAI3, SEC_RIFSC(51)),
+ STM32_GATE(CK_BUS_SAI4, "ck_icn_p_sai4", "ck_icn_apb2", 0, GATE_SAI4, SEC_RIFSC(52)),
+ STM32_GATE(CK_KER_SAI1, "ck_ker_sai1", "ck_flexgen_23", 0, GATE_SAI1, SEC_RIFSC(49)),
+ STM32_GATE(CK_KER_SAI2, "ck_ker_sai2", "ck_flexgen_24", 0, GATE_SAI2, SEC_RIFSC(50)),
+ STM32_GATE(CK_KER_SAI3, "ck_ker_sai3", "ck_flexgen_25", 0, GATE_SAI3, SEC_RIFSC(51)),
+ STM32_GATE(CK_KER_SAI4, "ck_ker_sai4", "ck_flexgen_25", 0, GATE_SAI4, SEC_RIFSC(52)),
+
+ /* SDMMC */
+ STM32_GATE(CK_KER_SDMMC1, "ck_ker_sdmmc1", "ck_flexgen_51", 0, GATE_SDMMC1,
+ SEC_RIFSC(76)),
+ STM32_GATE(CK_KER_SDMMC2, "ck_ker_sdmmc2", "ck_flexgen_52", 0, GATE_SDMMC2,
+ SEC_RIFSC(77)),
+ STM32_GATE(CK_KER_SDMMC3, "ck_ker_sdmmc3", "ck_flexgen_53", 0, GATE_SDMMC3,
+ SEC_RIFSC(78)),
+
+ /* SERC */
+ STM32_GATE(CK_BUS_SERC, "ck_icn_p_serc", "ck_icn_apb3", 0, GATE_SERC, SEC_RIFSC(110)),
+
+ /* SPDIF */
+ STM32_GATE(CK_KER_SPDIFRX, "ck_ker_spdifrx", "ck_flexgen_11", 0, GATE_SPDIFRX,
+ SEC_RIFSC(30)),
+
+ /* SPI */
+ STM32_GATE(CK_KER_SPI1, "ck_ker_spi1", "ck_flexgen_16", 0, GATE_SPI1, SEC_RIFSC(22)),
+ STM32_GATE(CK_KER_SPI2, "ck_ker_spi2", "ck_flexgen_10", 0, GATE_SPI2, SEC_RIFSC(23)),
+ STM32_GATE(CK_KER_SPI3, "ck_ker_spi3", "ck_flexgen_10", 0, GATE_SPI3, SEC_RIFSC(24)),
+ STM32_GATE(CK_KER_SPI4, "ck_ker_spi4", "ck_flexgen_17", 0, GATE_SPI4, SEC_RIFSC(25)),
+ STM32_GATE(CK_KER_SPI5, "ck_ker_spi5", "ck_flexgen_17", 0, GATE_SPI5, SEC_RIFSC(26)),
+ STM32_GATE(CK_KER_SPI6, "ck_ker_spi6", "ck_flexgen_18", 0, GATE_SPI6, SEC_RIFSC(27)),
+ STM32_GATE(CK_KER_SPI7, "ck_ker_spi7", "ck_flexgen_18", 0, GATE_SPI7, SEC_RIFSC(28)),
+ STM32_GATE(CK_KER_SPI8, "ck_ker_spi8", "ck_flexgen_37", 0, GATE_SPI8, SEC_RIFSC(29)),
+
+ /* STGEN */
+ STM32_GATE(CK_KER_STGEN, "ck_ker_stgen", "ck_flexgen_33", CLK_IGNORE_UNUSED, GATE_STGEN,
+ SEC_RIFSC(73)),
+
+ /* Timers */
+ STM32_GATE(CK_KER_TIM2, "ck_ker_tim2", "timg1_ck", 0, GATE_TIM2, SEC_RIFSC(1)),
+ STM32_GATE(CK_KER_TIM3, "ck_ker_tim3", "timg1_ck", 0, GATE_TIM3, SEC_RIFSC(2)),
+ STM32_GATE(CK_KER_TIM4, "ck_ker_tim4", "timg1_ck", 0, GATE_TIM4, SEC_RIFSC(3)),
+ STM32_GATE(CK_KER_TIM5, "ck_ker_tim5", "timg1_ck", 0, GATE_TIM5, SEC_RIFSC(4)),
+ STM32_GATE(CK_KER_TIM6, "ck_ker_tim6", "timg1_ck", 0, GATE_TIM6, SEC_RIFSC(5)),
+ STM32_GATE(CK_KER_TIM7, "ck_ker_tim7", "timg1_ck", 0, GATE_TIM7, SEC_RIFSC(6)),
+ STM32_GATE(CK_KER_TIM10, "ck_ker_tim10", "timg1_ck", 0, GATE_TIM10, SEC_RIFSC(8)),
+ STM32_GATE(CK_KER_TIM11, "ck_ker_tim11", "timg1_ck", 0, GATE_TIM11, SEC_RIFSC(9)),
+ STM32_GATE(CK_KER_TIM12, "ck_ker_tim12", "timg1_ck", 0, GATE_TIM12, SEC_RIFSC(10)),
+ STM32_GATE(CK_KER_TIM13, "ck_ker_tim13", "timg1_ck", 0, GATE_TIM13, SEC_RIFSC(11)),
+ STM32_GATE(CK_KER_TIM14, "ck_ker_tim14", "timg1_ck", 0, GATE_TIM14, SEC_RIFSC(12)),
+
+ STM32_GATE(CK_KER_TIM1, "ck_ker_tim1", "timg2_ck", 0, GATE_TIM1, SEC_RIFSC(0)),
+ STM32_GATE(CK_KER_TIM8, "ck_ker_tim8", "timg2_ck", 0, GATE_TIM8, SEC_RIFSC(7)),
+ STM32_GATE(CK_KER_TIM15, "ck_ker_tim15", "timg2_ck", 0, GATE_TIM15, SEC_RIFSC(13)),
+ STM32_GATE(CK_KER_TIM16, "ck_ker_tim16", "timg2_ck", 0, GATE_TIM16, SEC_RIFSC(14)),
+ STM32_GATE(CK_KER_TIM17, "ck_ker_tim17", "timg2_ck", 0, GATE_TIM17, SEC_RIFSC(15)),
+ STM32_GATE(CK_KER_TIM20, "ck_ker_tim20", "timg2_ck", 0, GATE_TIM20, SEC_RIFSC(20)),
+
+ /* UART/USART */
+ STM32_GATE(CK_KER_USART2, "ck_ker_usart2", "ck_flexgen_08", 0, GATE_USART2,
+ SEC_RIFSC(32)),
+ STM32_GATE(CK_KER_UART4, "ck_ker_uart4", "ck_flexgen_08", 0, GATE_UART4,
+ SEC_RIFSC(34)),
+ STM32_GATE(CK_KER_USART3, "ck_ker_usart3", "ck_flexgen_09", 0, GATE_USART3,
+ SEC_RIFSC(33)),
+ STM32_GATE(CK_KER_UART5, "ck_ker_uart5", "ck_flexgen_09", 0, GATE_UART5,
+ SEC_RIFSC(35)),
+ STM32_GATE(CK_KER_USART1, "ck_ker_usart1", "ck_flexgen_19", 0, GATE_USART1,
+ SEC_RIFSC(31)),
+ STM32_GATE(CK_KER_USART6, "ck_ker_usart6", "ck_flexgen_20", 0, GATE_USART6,
+ SEC_RIFSC(36)),
+ STM32_GATE(CK_KER_UART7, "ck_ker_uart7", "ck_flexgen_21", 0, GATE_UART7,
+ SEC_RIFSC(37)),
+ STM32_GATE(CK_KER_UART8, "ck_ker_uart8", "ck_flexgen_21", 0, GATE_UART8,
+ SEC_RIFSC(38)),
+ STM32_GATE(CK_KER_UART9, "ck_ker_uart9", "ck_flexgen_22", 0, GATE_UART9,
+ SEC_RIFSC(39)),
+
+ /* USB2PHY1 */
+ STM32_COMPOSITE_NODIV(CK_KER_USB2PHY1, "ck_ker_usb2phy1", 0, SEC_RIFSC(63),
+ GATE_USB2PHY1, MUX_USB2PHY1),
+
+ /* USBH */
+ STM32_GATE(CK_BUS_USB2OHCI, "ck_icn_m_usb2ohci", "ck_icn_hsl", 0, GATE_USBH,
+ SEC_RIFSC(63)),
+ STM32_GATE(CK_BUS_USB2EHCI, "ck_icn_m_usb2ehci", "ck_icn_hsl", 0, GATE_USBH,
+ SEC_RIFSC(63)),
+
+ /* USB2PHY2 */
+ STM32_COMPOSITE_NODIV(CK_KER_USB2PHY2EN, "ck_ker_usb2phy2_en", 0, SEC_RIFSC(66),
+ GATE_USB2PHY2, MUX_USB2PHY2),
+
+ /* USB3 PCIe COMBOPHY */
+ STM32_GATE(CK_BUS_USB3PCIEPHY, "ck_icn_p_usb3pciephy", "ck_icn_apb4", 0, GATE_USB3PCIEPHY,
+ SEC_RIFSC(67)),
+
+ STM32_COMPOSITE_NODIV(CK_KER_USB3PCIEPHY, "ck_ker_usb3pciephy", 0, SEC_RIFSC(67),
+ GATE_USB3PCIEPHY, MUX_USB3PCIEPHY),
+
+ /* USB3 DRD */
+ STM32_GATE(CK_BUS_USB3DR, "ck_icn_m_usb3dr", "ck_icn_hsl", 0, GATE_USB3DR,
+ SEC_RIFSC(66)),
+ STM32_GATE(CK_KER_USB2PHY2, "ck_ker_usb2phy2", "ck_flexgen_58", 0, GATE_USB3DR,
+ SEC_RIFSC(66)),
+
+ /* UCPD */
+ STM32_GATE(CK_BUS_USBTC, "ck_icn_p_usbtc", "ck_flexgen_35", 0, GATE_USBTC,
+ SEC_RIFSC(69)),
+ STM32_GATE(CK_KER_USBTC, "ck_ker_usbtc", "ck_flexgen_35", 0, GATE_USBTC,
+ SEC_RIFSC(69)),
+
+ /* VDEC / VENC */
+ STM32_GATE(CK_BUS_VDEC, "ck_icn_p_vdec", "ck_icn_apb4", 0, GATE_VDEC, SEC_RIFSC(89)),
+ STM32_GATE(CK_BUS_VENC, "ck_icn_p_venc", "ck_icn_apb4", 0, GATE_VENC, SEC_RIFSC(90)),
+
+ /* VREF */
+ STM32_GATE(CK_BUS_VREF, "ck_icn_p_vref", "ck_icn_apb3", 0, RCC_VREFCFGR,
+ SEC_RIFSC(106)),
+
+ /* WWDG */
+ STM32_GATE(CK_BUS_WWDG1, "ck_icn_p_wwdg1", "ck_icn_apb3", 0, GATE_WWDG1,
+ SEC_RIFSC(103)),
+ STM32_GATE(CK_BUS_WWDG2, "ck_icn_p_wwdg2", "ck_icn_ls_mcu", 0, GATE_WWDG2,
+ SEC_RIFSC(104)),
+};
+
+static const struct stm32_clock_match_data stm32mp25_data = {
+ .tab_clocks = stm32mp25_clock_cfg,
+ .num_clocks = ARRAY_SIZE(stm32mp25_clock_cfg),
+ .clock_data = &(const struct clk_stm32_clock_data) {
+ .num_gates = ARRAY_SIZE(stm32mp25_gates),
+ .gates = stm32mp25_gates,
+ .muxes = stm32mp25_muxes,
+ },
+ .check_security = stm32mp25_check_security,
+
+};
+
+static int stm32mp25_clk_probe(struct udevice *dev)
+{
+ fdt_addr_t base = dev_read_addr(dev->parent);
+ struct udevice *scmi;
+
+ if (base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ /* force SCMI probe to register all SCMI clocks */
+ uclass_get_device_by_driver(UCLASS_CLK, DM_DRIVER_GET(scmi_clock), &scmi);
+
+ stm32_rcc_init(dev, &stm32mp25_data);
+
+ return 0;
+}
+
+U_BOOT_DRIVER(stm32mp25_clock) = {
+ .name = "stm32mp25_clk",
+ .id = UCLASS_CLK,
+ .ops = &stm32_clk_ops,
+ .priv_auto = sizeof(struct stm32mp_rcc_priv),
+ .probe = stm32mp25_clk_probe,
+};
diff --git a/drivers/clk/stm32/stm32mp13_rcc.h b/drivers/clk/stm32/stm32mp13_rcc.h
index e7191b428af..b9b44b213c3 100644
--- a/drivers/clk/stm32/stm32mp13_rcc.h
+++ b/drivers/clk/stm32/stm32mp13_rcc.h
@@ -285,4 +285,97 @@
#define RCC_AHB6SECSR_ETH2MACSECF 30
#define RCC_AHB6SECSR_ETH2STPSECF 31
+/* Fields of RCC_BDCR register */
+#define RCC_BDCR_LSEON BIT(0)
+#define RCC_BDCR_LSEBYP BIT(1)
+#define RCC_BDCR_LSERDY BIT(2)
+#define RCC_BDCR_DIGBYP BIT(3)
+#define RCC_BDCR_LSEDRV_MASK GENMASK(5, 4)
+#define RCC_BDCR_LSEDRV_SHIFT 4
+#define RCC_BDCR_LSECSSON BIT(8)
+#define RCC_BDCR_RTCCKEN BIT(20)
+#define RCC_BDCR_RTCSRC_MASK GENMASK(17, 16)
+#define RCC_BDCR_RTCSRC_SHIFT 16
+
+/* Fields of RCC_RDLSICR register */
+#define RCC_RDLSICR_LSION BIT(0)
+#define RCC_RDLSICR_LSIRDY BIT(1)
+
+/* used for ALL PLLNCR registers */
+#define RCC_PLLNCR_PLLON BIT(0)
+#define RCC_PLLNCR_PLLRDY BIT(1)
+#define RCC_PLLNCR_SSCG_CTRL BIT(2)
+#define RCC_PLLNCR_DIVPEN BIT(4)
+#define RCC_PLLNCR_DIVQEN BIT(5)
+#define RCC_PLLNCR_DIVREN BIT(6)
+#define RCC_PLLNCR_DIVEN_SHIFT 4
+
+/* used for ALL PLLNCFGR1 registers */
+#define RCC_PLLNCFGR1_DIVM_SHIFT 16
+#define RCC_PLLNCFGR1_DIVM_MASK GENMASK(21, 16)
+#define RCC_PLLNCFGR1_DIVN_SHIFT 0
+#define RCC_PLLNCFGR1_DIVN_MASK GENMASK(8, 0)
+/* only for PLL3 and PLL4 */
+#define RCC_PLLNCFGR1_IFRGE_SHIFT 24
+#define RCC_PLLNCFGR1_IFRGE_MASK GENMASK(25, 24)
+
+/* used for ALL PLLNCFGR2 registers , using stm32mp1_div_id */
+#define RCC_PLLNCFGR2_SHIFT(div_id) ((div_id) * 8)
+#define RCC_PLLNCFGR2_DIVX_MASK GENMASK(6, 0)
+#define RCC_PLLNCFGR2_DIVP_SHIFT RCC_PLLNCFGR2_SHIFT(_DIV_P)
+#define RCC_PLLNCFGR2_DIVP_MASK GENMASK(6, 0)
+#define RCC_PLLNCFGR2_DIVQ_SHIFT RCC_PLLNCFGR2_SHIFT(_DIV_Q)
+#define RCC_PLLNCFGR2_DIVQ_MASK GENMASK(14, 8)
+#define RCC_PLLNCFGR2_DIVR_SHIFT RCC_PLLNCFGR2_SHIFT(_DIV_R)
+#define RCC_PLLNCFGR2_DIVR_MASK GENMASK(22, 16)
+
+/* used for ALL PLLNFRACR registers */
+#define RCC_PLLNFRACR_FRACV_SHIFT 3
+#define RCC_PLLNFRACR_FRACV_MASK GENMASK(15, 3)
+#define RCC_PLLNFRACR_FRACLE BIT(16)
+
+/* used for ALL PLLNCSGR registers */
+#define RCC_PLLNCSGR_INC_STEP_SHIFT 16
+#define RCC_PLLNCSGR_INC_STEP_MASK GENMASK(30, 16)
+#define RCC_PLLNCSGR_MOD_PER_SHIFT 0
+#define RCC_PLLNCSGR_MOD_PER_MASK GENMASK(12, 0)
+#define RCC_PLLNCSGR_SSCG_MODE_SHIFT 15
+#define RCC_PLLNCSGR_SSCG_MODE_MASK BIT(15)
+
+/* used for RCC_OCENSETR and RCC_OCENCLRR registers */
+#define RCC_OCENR_HSION BIT(0)
+#define RCC_OCENR_CSION BIT(4)
+#define RCC_OCENR_DIGBYP BIT(7)
+#define RCC_OCENR_HSEON BIT(8)
+#define RCC_OCENR_HSEBYP BIT(10)
+#define RCC_OCENR_HSECSSON BIT(11)
+
+/* Fields of RCC_OCRDYR register */
+#define RCC_OCRDYR_HSIRDY BIT(0)
+#define RCC_OCRDYR_HSIDIVRDY BIT(2)
+#define RCC_OCRDYR_CSIRDY BIT(4)
+#define RCC_OCRDYR_HSERDY BIT(8)
+
+/* Fields of DDRITFCR register */
+#define RCC_DDRITFCR_DDRCKMOD_MASK GENMASK(22, 20)
+#define RCC_DDRITFCR_DDRCKMOD_SHIFT 20
+#define RCC_DDRITFCR_DDRCKMOD_SSR 0
+
+/* Fields of RCC_HSICFGR register */
+#define RCC_HSICFGR_HSIDIV_MASK GENMASK(1, 0)
+
+/* used for MCO related operations */
+#define RCC_MCOCFG_MCOON BIT(12)
+#define RCC_MCOCFG_MCODIV_MASK GENMASK(7, 4)
+#define RCC_MCOCFG_MCODIV_SHIFT 4
+#define RCC_MCOCFG_MCOSRC_MASK GENMASK(2, 0)
+
+/* used for most of SELR register */
+#define RCC_SELR_SRC_MASK GENMASK(2, 0)
+#define RCC_SELR_SRCRDY BIT(31)
+
+/* used for most of DIVR register : max div for RTC */
+#define RCC_DIVR_DIV_MASK GENMASK(5, 0)
+#define RCC_DIVR_DIVRDY BIT(31)
+
#endif /* STM32MP13_RCC_H */