diff options
Diffstat (limited to 'drivers')
123 files changed, 6095 insertions, 476 deletions
diff --git a/drivers/ata/dwc_ahsata_priv.h b/drivers/ata/dwc_ahsata_priv.h index 0c2cd5446b5..f2a118420f9 100644 --- a/drivers/ata/dwc_ahsata_priv.h +++ b/drivers/ata/dwc_ahsata_priv.h @@ -117,8 +117,8 @@ #define SATA_HOST_GPARAM1R_PHY_TYPE 0x00001000 #define SATA_HOST_GPARAM1R_RETURN_ERR 0x00000400 #define SATA_HOST_GPARAM1R_AHB_ENDIAN_MASK 0x00000300 -#define SATA_HOST_GPARAM1R_S_HADDR 0X00000080 -#define SATA_HOST_GPARAM1R_M_HADDR 0X00000040 +#define SATA_HOST_GPARAM1R_S_HADDR 0x00000080 +#define SATA_HOST_GPARAM1R_M_HADDR 0x00000040 /* Global Parameter 2 Register */ #define SATA_HOST_GPARAM2R_DEV_CP 0x00004000 diff --git a/drivers/button/button-qcom-pmic.c b/drivers/button/button-qcom-pmic.c index e3bb9bd758a..85addfe32a2 100644 --- a/drivers/button/button-qcom-pmic.c +++ b/drivers/button/button-qcom-pmic.c @@ -143,6 +143,21 @@ static int qcom_pwrkey_probe(struct udevice *dev) priv->base = base; + ret = dev_read_u32(dev, "linux,code", &priv->code); + if (ret == 0) { + /* convert key, if read OK */ + switch (priv->code) { + case KEY_VOLUMEDOWN: + priv->code = KEY_DOWN; + uc_plat->label = "Volume Down"; + break; + case KEY_VOLUMEUP: + priv->code = KEY_UP; + uc_plat->label = "Volume Up"; + break; + } + } + /* Do a sanity check */ ret = pmic_reg_read(priv->pmic, priv->base + REG_TYPE); if (ret != 0x1 && ret != 0xb) { diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 19aa2ffa539..ef1e5355be8 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 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", ®, 19, 6)); + dev_clk_dm(dev, SANDBOX_CLK_ECSPI_ROOT, + sandbox_clk_divider("ecspi_root", "pll3_60m", ®, 19, 6)); reg = 0; - clk_dm(SANDBOX_CLK_ECSPI0, - sandbox_clk_gate("ecspi0", "ecspi_root", ®, 0, 0)); + dev_clk_dm(dev, SANDBOX_CLK_ECSPI0, + sandbox_clk_gate("ecspi0", "ecspi_root", ®, 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", ®, 16, 1, usdhc_sels, - ARRAY_SIZE(usdhc_sels))); + dev_clk_dm(dev, SANDBOX_CLK_USDHC1_SEL, + sandbox_clk_mux("usdhc1_sel", ®, 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", ®, 17, 1, usdhc_sels, - ARRAY_SIZE(usdhc_sels))); + dev_clk_dm(dev, SANDBOX_CLK_USDHC2_SEL, + sandbox_clk_mux("usdhc2_sel", ®, 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), - ®, CLK_SET_RATE_UNGATE)); + dev_clk_dm(dev, SANDBOX_CLK_I2C, + sandbox_clk_composite("i2c", i2c_sels, ARRAY_SIZE(i2c_sels), + ®, 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/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/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-apq8016.c b/drivers/clk/qcom/clock-apq8016.c index 6a53f900a9e..b7bd9c9a342 100644 --- a/drivers/clk/qcom/clock-apq8016.c +++ b/drivers/clk/qcom/clock-apq8016.c @@ -23,10 +23,7 @@ #define APCS_GPLL_ENA_VOTE (0x45000) #define APCS_CLOCK_BRANCH_ENA_VOTE (0x45004) -#define SDCC_BCR(n) ((n * 0x1000) + 0x41000) -#define SDCC_CMD_RCGR(n) (((n + 1) * 0x1000) + 0x41004) -#define SDCC_APPS_CBCR(n) ((n * 0x1000) + 0x41018) -#define SDCC_AHB_CBCR(n) ((n * 0x1000) + 0x4101C) +#define SDCC_CMD_RCGR(n) (((n) * 0x1000) + 0x42004) /* BLSP1 AHB clock (root clock for BLSP) */ #define BLSP1_AHB_CBCR 0x1008 @@ -54,9 +51,13 @@ static struct vote_clk gcc_blsp1_ahb_clk = { }; static const struct gate_clk apq8016_clks[] = { - GATE_CLK(GCC_PRNG_AHB_CLK, 0x45004, BIT(8)), - GATE_CLK(GCC_USB_HS_AHB_CLK, 0x41008, BIT(0)), - GATE_CLK(GCC_USB_HS_SYSTEM_CLK, 0x41004, BIT(0)), + GATE_CLK_POLLED(GCC_PRNG_AHB_CLK, 0x45004, BIT(8), 0x13004), + GATE_CLK_POLLED(GCC_SDCC1_AHB_CLK, 0x4201c, BIT(0), 0x4201c), + GATE_CLK_POLLED(GCC_SDCC1_APPS_CLK, 0x42018, BIT(0), 0x42018), + GATE_CLK_POLLED(GCC_SDCC2_AHB_CLK, 0x4301c, BIT(0), 0x4301c), + GATE_CLK_POLLED(GCC_SDCC2_APPS_CLK, 0x43018, BIT(0), 0x43018), + GATE_CLK_POLLED(GCC_USB_HS_AHB_CLK, 0x41008, BIT(0), 0x41008), + GATE_CLK_POLLED(GCC_USB_HS_SYSTEM_CLK, 0x41004, BIT(0), 0x41004), }; /* SDHCI */ @@ -67,12 +68,10 @@ static int apq8016_clk_init_sdc(struct msm_clk_priv *priv, int slot, uint rate) if (rate == 200000000) div = 4; - clk_enable_cbc(priv->base + SDCC_AHB_CBCR(slot)); /* 800Mhz/div, gpll0 */ clk_rcg_set_rate_mnd(priv->base, SDCC_CMD_RCGR(slot), div, 0, 0, CFG_CLK_SRC_GPLL0, 8); clk_enable_gpll0(priv->base, &gpll0_vote_clk); - clk_enable_cbc(priv->base + SDCC_APPS_CBCR(slot)); return rate; } 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.c b/drivers/clk/qcom/clock-qcom.c index 7687bbe6a23..6b46d9db744 100644 --- a/drivers/clk/qcom/clock-qcom.c +++ b/drivers/clk/qcom/clock-qcom.c @@ -74,6 +74,33 @@ void clk_enable_vote_clk(phys_addr_t base, const struct vote_clk *vclk) } while ((val != BRANCH_ON_VAL) && (val != BRANCH_NOC_FSM_ON_VAL)); } +int qcom_gate_clk_en(const struct msm_clk_priv *priv, unsigned long id) +{ + if (id >= priv->data->num_clks || priv->data->clks[id].reg == 0) { + log_err("gcc@%#08llx: unknown clock ID %lu!\n", + priv->base, id); + return -ENOENT; + } + + setbits_le32(priv->base + priv->data->clks[id].reg, priv->data->clks[id].en_val); + if (priv->data->clks[id].cbcr_reg) { + unsigned int count; + u32 val; + + for (count = 0; count < 200; count++) { + val = readl(priv->base + priv->data->clks[id].cbcr_reg); + val &= BRANCH_CHECK_MASK; + if (val == BRANCH_ON_VAL || val == BRANCH_NOC_FSM_ON_VAL) + break; + udelay(1); + } + if (WARN(count == 200, "WARNING: Clock @ %#lx [%#010x] stuck at off\n", + priv->data->clks[id].cbcr_reg, val)) + return -EBUSY; + } + return 0; +} + #define APPS_CMD_RCGR_UPDATE BIT(0) /* Update clock command via CMD_RCGR */ diff --git a/drivers/clk/qcom/clock-qcom.h b/drivers/clk/qcom/clock-qcom.h index f43edea2525..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) @@ -52,13 +53,20 @@ struct freq_tbl { struct gate_clk { uintptr_t reg; u32 en_val; + uintptr_t cbcr_reg; const char *name; }; +/* + * GATE_CLK() is deprecated: Use GATE_CLK_POLLED() instead to ensure the clock + * is running before we start making use of devices or registers. + */ #ifdef DEBUG -#define GATE_CLK(clk, reg, val) [clk] = { reg, val, #clk } +#define GATE_CLK(clk, reg, val) [clk] = { reg, val, 0, #clk } +#define GATE_CLK_POLLED(clk, en_reg, val, cbcr_reg) [clk] = { en_reg, val, cbcr_reg, #clk } #else -#define GATE_CLK(clk, reg, val) [clk] = { reg, val, NULL } +#define GATE_CLK(clk, reg, val) [clk] = { reg, val, 0, NULL } +#define GATE_CLK_POLLED(clk, en_reg, val, cbcr_reg) [clk] = { en_reg, val, cbcr_reg, NULL } #endif struct qcom_reset_map { @@ -107,19 +115,6 @@ void clk_rcg_set_rate(phys_addr_t base, uint32_t cmd_rcgr, int div, int source); void clk_phy_mux_enable(phys_addr_t base, uint32_t cmd_rcgr, bool enabled); -static inline int qcom_gate_clk_en(const struct msm_clk_priv *priv, unsigned long id) -{ - u32 val; - if (id >= priv->data->num_clks || priv->data->clks[id].reg == 0) { - log_err("gcc@%#08llx: unknown clock ID %lu!\n", - priv->base, id); - return -ENOENT; - } - - val = readl(priv->base + priv->data->clks[id].reg); - writel(val | priv->data->clks[id].en_val, priv->base + priv->data->clks[id].reg); - - return 0; -} +int qcom_gate_clk_en(const struct msm_clk_priv *priv, unsigned long id); #endif 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/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 */ diff --git a/drivers/core/read.c b/drivers/core/read.c index 55c19f335ae..c0d7a969db2 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -38,8 +38,8 @@ int dev_read_u32(const struct udevice *dev, const char *propname, u32 *outp) return ofnode_read_u32(dev_ofnode(dev), propname, outp); } -int dev_read_u32_default(const struct udevice *dev, const char *propname, - int def) +u32 dev_read_u32_default(const struct udevice *dev, const char *propname, + u32 def) { return ofnode_read_u32_default(dev_ofnode(dev), propname, def); } @@ -62,8 +62,8 @@ int dev_read_s32(const struct udevice *dev, const char *propname, s32 *outp) return ofnode_read_u32(dev_ofnode(dev), propname, (u32 *)outp); } -int dev_read_s32_default(const struct udevice *dev, const char *propname, - int def) +s32 dev_read_s32_default(const struct udevice *dev, const char *propname, + s32 def) { return ofnode_read_u32_default(dev_ofnode(dev), propname, def); } diff --git a/drivers/crypto/fsl/jr.c b/drivers/crypto/fsl/jr.c index 1d95d2bff27..8f7a821ebf3 100644 --- a/drivers/crypto/fsl/jr.c +++ b/drivers/crypto/fsl/jr.c @@ -217,6 +217,13 @@ static int jr_enqueue(uint32_t *desc_addr, jr->head = (head + 1) & (jr->size - 1); + /* Invalidate output ring */ + start = (unsigned long)jr->output_ring & + ~(ARCH_DMA_MINALIGN - 1); + end = ALIGN((unsigned long)jr->output_ring + jr->op_size, + ARCH_DMA_MINALIGN); + invalidate_dcache_range(start, end); + sec_out32(®s->irja, 1); return 0; @@ -236,7 +243,6 @@ static int jr_dequeue(int sec_idx, struct caam_regs *caam) #else uint32_t *addr; #endif - unsigned long start, end; while (sec_in32(®s->orsf) && CIRC_CNT(jr->head, jr->tail, jr->size)) { @@ -244,11 +250,6 @@ static int jr_dequeue(int sec_idx, struct caam_regs *caam) found = 0; caam_dma_addr_t op_desc; - - /* Invalidate output ring */ - start = (unsigned long)jr->output_ring & ~(ARCH_DMA_MINALIGN - 1); - end = ALIGN((unsigned long)jr->output_ring + jr->op_size, ARCH_DMA_MINALIGN); - invalidate_dcache_range(start, end); #ifdef CONFIG_CAAM_64BIT /* Read the 64 bit Descriptor address from Output Ring. * The 32 bit hign and low part of the address will @@ -282,13 +283,8 @@ static int jr_dequeue(int sec_idx, struct caam_regs *caam) } /* Error condition if match not found */ - if (!found) { - int slots_full = sec_in32(®s->orsf); - - jr->tail = (jr->tail + slots_full) & (jr->size - 1); - sec_out32(®s->orjr, slots_full); + if (!found) return -1; - } jr->info[idx].op_done = 1; callback = (void *)jr->info[idx].callback; @@ -300,14 +296,14 @@ static int jr_dequeue(int sec_idx, struct caam_regs *caam) */ if (idx == tail) do { - jr->info[tail].op_done = 0; tail = (tail + 1) & (jr->size - 1); } while (jr->info[tail].op_done); jr->tail = tail; - + jr->read_idx = (jr->read_idx + 1) & (jr->size - 1); sec_out32(®s->orjr, 1); + jr->info[idx].op_done = 0; callback(status, arg); } @@ -382,6 +378,7 @@ static int jr_sw_cleanup(uint8_t sec_idx, struct caam_regs *caam) jr->head = 0; jr->tail = 0; + jr->read_idx = 0; jr->write_idx = 0; memset(jr->info, 0, sizeof(jr->info)); memset(jr->input_ring, 0, jr->size * sizeof(caam_dma_addr_t)); diff --git a/drivers/crypto/fsl/jr.h b/drivers/crypto/fsl/jr.h index 8d5ca03e501..b136cd8d05a 100644 --- a/drivers/crypto/fsl/jr.h +++ b/drivers/crypto/fsl/jr.h @@ -83,6 +83,10 @@ struct jobring { * in-order job completion */ int tail; + /* Read index of the output ring. It may not match with tail in case + * of out of order completetion + */ + int read_idx; /* Write index to input ring. Would be always equal to head */ int write_idx; /* Size of the rings. */ diff --git a/drivers/ddr/altera/iossm_mailbox.c b/drivers/ddr/altera/iossm_mailbox.c index fc09dde3f9e..21f94959a04 100644 --- a/drivers/ddr/altera/iossm_mailbox.c +++ b/drivers/ddr/altera/iossm_mailbox.c @@ -41,7 +41,7 @@ /* Offset of Mailbox Read-only Registers */ #define IOSSM_MAILBOX_HEADER_OFFSET 0x0 -#define IOSSM_MEM_INTF_INFO_0_OFFSET 0X200 +#define IOSSM_MEM_INTF_INFO_0_OFFSET 0x200 #define IOSSM_MEM_INTF_INFO_1_OFFSET 0x280 #define IOSSM_MEM_TECHNOLOGY_INTF0_OFFSET 0x210 #define IOSSM_MEM_TECHNOLOGY_INTF1_OFFSET 0x290 diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c index c19eb919388..a91671755e1 100644 --- a/drivers/dfu/dfu_mmc.c +++ b/drivers/dfu/dfu_mmc.c @@ -117,7 +117,7 @@ static int mmc_file_op(enum dfu_op op, struct dfu_entity *dfu, return -1; } - snprintf(dev_part_str, sizeof(dev_part_str), "%d:%d", + snprintf(dev_part_str, sizeof(dev_part_str), "%d:%x", dfu->data.mmc.dev, dfu->data.mmc.part); ret = fs_set_blk_dev("mmc", dev_part_str, fstype); diff --git a/drivers/dfu/dfu_scsi.c b/drivers/dfu/dfu_scsi.c index 9f95194784c..d99b05d23ac 100644 --- a/drivers/dfu/dfu_scsi.c +++ b/drivers/dfu/dfu_scsi.c @@ -96,7 +96,7 @@ static int scsi_file_op(enum dfu_op op, struct dfu_entity *dfu, u64 offset, void return -1; } - snprintf(dev_part_str, sizeof(dev_part_str), "%d:%d", dfu->data.scsi.dev, + snprintf(dev_part_str, sizeof(dev_part_str), "%d:%x", dfu->data.scsi.dev, dfu->data.scsi.part); ret = fs_set_blk_dev("scsi", dev_part_str, fstype); @@ -342,11 +342,6 @@ int dfu_fill_entity_scsi(struct dfu_entity *dfu, char *devstr, char **argv, int return -EINVAL; } - if (scsi_scan(false)) { - pr_err("Couldn't init scsi device.\n"); - return -ENODEV; - } - ret = find_scsi_device(dfu->data.scsi.lun, &scsi); if (ret < 0) { pr_err("Couldn't find scsi device no. %d.\n", dfu->data.scsi.lun); diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index 344df9454b3..8013afef304 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -279,6 +279,101 @@ static int ti_sci_do_xfer(struct ti_sci_info *info, } /** + * ti_sci_cmd_query_dm_cap() - Command to query DM firmware's capabilities + * @handle: Pointer to TI SCI handle + * @fw_caps: Pointer to firmware capabilities + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_query_dm_cap(struct ti_sci_handle *handle, u64 *fw_caps) +{ + struct ti_sci_query_fw_caps_resp *cap_info; + struct ti_sci_msg_hdr hdr; + struct ti_sci_info *info; + struct ti_sci_xfer *xfer; + int ret; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + + xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_QUERY_FW_CAPS, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + (u32 *)&hdr, sizeof(struct ti_sci_msg_hdr), + sizeof(*cap_info)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + return ret; + } + + ret = ti_sci_do_xfer(info, xfer); + if (ret) + return ret; + + cap_info = (struct ti_sci_query_fw_caps_resp *)xfer->tx_message.buf; + + *fw_caps = cap_info->fw_caps; + + return 0; +} + +/** + * ti_sci_cmd_get_dm_version() - command to get the DM version of the SCI + * entity + * @handle: Pointer to TI SCI handle + * @dm_info: Pointer to DM version information structure + * + * Return: 0 if all went fine, else return appropriate error. + */ + +static int ti_sci_cmd_get_dm_version(struct ti_sci_handle *handle, + struct ti_sci_dm_version_info *dm_info) +{ + struct ti_sci_msg_dm_resp_version *ver_info; + struct ti_sci_msg_hdr hdr; + struct ti_sci_info *info; + struct ti_sci_xfer *xfer; + int ret; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle || !dm_info) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + + xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_DM_VERSION, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + (u32 *)&hdr, sizeof(struct ti_sci_msg_hdr), + sizeof(*ver_info)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + return ret; + } + + ret = ti_sci_do_xfer(info, xfer); + if (ret) + return ret; + + ver_info = (struct ti_sci_msg_dm_resp_version *)xfer->tx_message.buf; + + dm_info->abi_major = ver_info->abi_major; + dm_info->abi_minor = ver_info->abi_minor; + dm_info->dm_ver = ver_info->version; + dm_info->patch_ver = ver_info->patch_version; + dm_info->sub_ver = ver_info->sub_version; + strlcpy(dm_info->sci_server_version, ver_info->sci_server_version, + sizeof(ver_info->sci_server_version)); + strlcpy(dm_info->rm_pm_hal_version, ver_info->rm_pm_hal_version, + sizeof(ver_info->rm_pm_hal_version)); + + return 0; +} + +/** * ti_sci_cmd_get_revision() - command to get the revision of the SCI entity * @handle: pointer to TI SCI handle * @@ -2624,6 +2719,7 @@ static void ti_sci_setup_ops(struct ti_sci_info *info) struct ti_sci_dev_ops *dops = &ops->dev_ops; struct ti_sci_clk_ops *cops = &ops->clk_ops; struct ti_sci_core_ops *core_ops = &ops->core_ops; + struct ti_sci_firmware_ops *fw_ops = &ops->fw_ops; struct ti_sci_rm_core_ops *rm_core_ops = &ops->rm_core_ops; struct ti_sci_proc_ops *pops = &ops->proc_ops; struct ti_sci_rm_ringacc_ops *rops = &ops->rm_ring_ops; @@ -2694,6 +2790,9 @@ static void ti_sci_setup_ops(struct ti_sci_info *info) fwl_ops->set_fwl_region = ti_sci_cmd_set_fwl_region; fwl_ops->get_fwl_region = ti_sci_cmd_get_fwl_region; fwl_ops->change_fwl_owner = ti_sci_cmd_change_fwl_owner; + + fw_ops->get_dm_version = ti_sci_cmd_get_dm_version; + fw_ops->query_dm_cap = ti_sci_cmd_query_dm_cap; } /** diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h index bb8bc7beead..ce50bf6800e 100644 --- a/drivers/firmware/ti_sci.h +++ b/drivers/firmware/ti_sci.h @@ -26,7 +26,9 @@ #define TI_SCI_MSG_BOARD_CONFIG_RM 0x000c #define TI_SCI_MSG_BOARD_CONFIG_SECURITY 0x000d #define TI_SCI_MSG_BOARD_CONFIG_PM 0x000e +#define TI_SCI_MSG_DM_VERSION 0x000f #define TISCI_MSG_QUERY_MSMC 0x0020 +#define TI_SCI_MSG_QUERY_FW_CAPS 0x0022 /* Device requests */ #define TI_SCI_MSG_SET_DEVICE_STATE 0x0200 @@ -135,6 +137,46 @@ struct ti_sci_msg_resp_version { } __packed; /** + * struct ti_sci_msg_dm_resp_version - Response for a message + * @hdr: Generic header + * @version: Version number of the firmware + * @sub_version: Sub-version number of the firmware + * @patch_version: Patch version number of the firmware + * @abi_major: Major version of the ABI that firmware supports + * @abi_minor: Minor version of the ABI that firmware supports + * @sci_server_version: String describing the SCI server version + * @rm_pm_hal_version: String describing the RM PM HAL version + * + * In general, ABI version changes follow the rule that minor version increments + * are backward compatible. Major revision changes in ABI may not be + * backward compatible. + * + * Response to a message with message type TI_SCI_MSG_DM_VERSION + */ +struct ti_sci_msg_dm_resp_version { + struct ti_sci_msg_hdr hdr; + u16 version; + u8 sub_version; + u8 patch_version; + u8 abi_major; + u8 abi_minor; + char rm_pm_hal_version[12]; + char sci_server_version[26]; +} __packed; + +/** + * struct ti_sci_query_fw_caps_resp - Response for a message + * @hdr: Generic header + * @fw_caps: 64-bit value representing the FW/SOC capabilities. + * + * Response to a message with message type TI_SCI_MSG_QUERY_FW_CAPS + */ +struct ti_sci_query_fw_caps_resp { + struct ti_sci_msg_hdr hdr; + u64 fw_caps; +} __packed; + +/** * struct ti_sci_msg_req_reboot - Reboot the SoC * @hdr: Generic Header * @domain: Domain to be reset, 0 for full SoC reboot. diff --git a/drivers/fpga/intel_sdm_mb.c b/drivers/fpga/intel_sdm_mb.c index 5fe4dbdfd32..a2f3b160a73 100644 --- a/drivers/fpga/intel_sdm_mb.c +++ b/drivers/fpga/intel_sdm_mb.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Intel Corporation <www.intel.com> + * Copyright (C) 2025 Altera Corporation <www.altera.com> */ #include <altera.h> @@ -9,6 +10,8 @@ #include <watchdog.h> #include <asm/arch/mailbox_s10.h> #include <asm/arch/smc_api.h> +#include <asm/cache.h> +#include <cpu_func.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/intel-smc.h> @@ -738,6 +741,8 @@ int intel_sdm_mb_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size) debug("Invoking FPGA_CONFIG_START...\n"); + flush_dcache_range((unsigned long)rbf_data, (unsigned long)(rbf_data + rbf_size)); + ret = invoke_smc(INTEL_SIP_SMC_FPGA_CONFIG_START, &arg, 1, NULL, 0); if (ret) { @@ -1023,6 +1028,8 @@ int intel_sdm_mb_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size) u32 resp_len = 2; u32 resp_buf[2]; + flush_dcache_range((unsigned long)rbf_data, (unsigned long)(rbf_data + rbf_size)); + debug("Sending MBOX_RECONFIG...\n"); ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_RECONFIG, MBOX_CMD_DIRECT, 0, NULL, 0, &resp_len, resp_buf); diff --git a/drivers/gpio/msm_gpio.c b/drivers/gpio/msm_gpio.c index 6783fc756f4..7de332c66ae 100644 --- a/drivers/gpio/msm_gpio.c +++ b/drivers/gpio/msm_gpio.c @@ -202,7 +202,7 @@ static int msm_gpio_get_value(struct udevice *dev, unsigned int gpio) if (qcom_is_special_pin(priv->pin_data, gpio)) return msm_gpio_get_value_special(priv, gpio); - return !!(readl(priv->base + GPIO_IN_OUT_REG(dev, gpio)) >> GPIO_IN); + return !!(readl(priv->base + GPIO_IN_OUT_REG(dev, gpio)) & BIT(GPIO_IN)); } static int msm_gpio_get_function_special(struct msm_gpio_bank *priv, diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c index e8c1623d41f..a54976e7889 100644 --- a/drivers/i2c/designware_i2c.c +++ b/drivers/i2c/designware_i2c.c @@ -404,7 +404,7 @@ static int i2c_wait_for_bb(struct i2c_regs *i2c_base) /* Evaluate timeout */ if (get_timer(start_time_bb) > (unsigned long)(I2C_BYTE_TO_BB)) - return 1; + return -ETIMEDOUT; } return 0; @@ -413,8 +413,10 @@ static int i2c_wait_for_bb(struct i2c_regs *i2c_base) static int i2c_xfer_init(struct i2c_regs *i2c_base, uchar chip, uint addr, int alen) { - if (i2c_wait_for_bb(i2c_base)) - return 1; + int ret = i2c_wait_for_bb(i2c_base); + + if (ret) + return ret; i2c_setaddress(i2c_base, chip); while (alen) { @@ -429,6 +431,7 @@ static int i2c_xfer_init(struct i2c_regs *i2c_base, uchar chip, uint addr, static int i2c_xfer_finish(struct i2c_regs *i2c_base) { ulong start_stop_det = get_timer(0); + int ret; while (1) { if ((readl(&i2c_base->ic_raw_intr_stat) & IC_STOP_DET)) { @@ -439,9 +442,10 @@ static int i2c_xfer_finish(struct i2c_regs *i2c_base) } } - if (i2c_wait_for_bb(i2c_base)) { + ret = i2c_wait_for_bb(i2c_base); + if (ret) { printf("Timed out waiting for bus\n"); - return 1; + return ret; } i2c_flush_rxfifo(i2c_base); @@ -464,6 +468,7 @@ static int __dw_i2c_read(struct i2c_regs *i2c_base, u8 dev, uint addr, { unsigned long start_time_rx; unsigned int active = 0; + int ret; #ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW /* @@ -484,8 +489,9 @@ static int __dw_i2c_read(struct i2c_regs *i2c_base, u8 dev, uint addr, addr); #endif - if (i2c_xfer_init(i2c_base, dev, addr, alen)) - return 1; + ret = i2c_xfer_init(i2c_base, dev, addr, alen); + if (ret) + return ret; start_time_rx = get_timer(0); while (len) { @@ -510,7 +516,7 @@ static int __dw_i2c_read(struct i2c_regs *i2c_base, u8 dev, uint addr, start_time_rx = get_timer(0); active = 0; } else if (get_timer(start_time_rx) > I2C_BYTE_TO) { - return 1; + return -ETIMEDOUT; } } @@ -532,6 +538,7 @@ static int __dw_i2c_write(struct i2c_regs *i2c_base, u8 dev, uint addr, { int nb = len; unsigned long start_time_tx; + int ret; #ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW /* @@ -552,8 +559,9 @@ static int __dw_i2c_write(struct i2c_regs *i2c_base, u8 dev, uint addr, addr); #endif - if (i2c_xfer_init(i2c_base, dev, addr, alen)) - return 1; + ret = i2c_xfer_init(i2c_base, dev, addr, alen); + if (ret) + return ret; start_time_tx = get_timer(0); while (len) { @@ -569,7 +577,7 @@ static int __dw_i2c_write(struct i2c_regs *i2c_base, u8 dev, uint addr, } else if (get_timer(start_time_tx) > (nb * I2C_BYTE_TO)) { printf("Timed out. i2c write Failed\n"); - return 1; + return -ETIMEDOUT; } } diff --git a/drivers/iommu/qcom-hyp-smmu.c b/drivers/iommu/qcom-hyp-smmu.c index c1b95bc8b8c..2e51ce4f242 100644 --- a/drivers/iommu/qcom-hyp-smmu.c +++ b/drivers/iommu/qcom-hyp-smmu.c @@ -11,6 +11,7 @@ #include <dm.h> #include <iommu.h> #include <linux/bitfield.h> +#include <linux/bug.h> #include <linux/list.h> #include <linux/err.h> #include <lmb.h> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index ffc5868c0dd..8b8f6309ada 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -114,6 +114,14 @@ config ROCKCHIP_IODOMAIN for the IO-domain setting of the SoC to match the voltage supplied by the regulators. +config SPL_ROCKCHIP_IODOMAIN + bool "Rockchip IO-domain driver support in SPL" + depends on SPL_MISC && SPL_DM_REGULATOR && ARCH_ROCKCHIP + help + Enable support for IO-domains in Rockchip SoCs in SPL. It is necessary + for the IO-domain setting of the SoC to match the voltage supplied + by the regulators. + config SIFIVE_OTP bool "SiFive eMemory OTP driver" depends on MISC diff --git a/drivers/misc/rockchip-io-domain.c b/drivers/misc/rockchip-io-domain.c index 025b6049a9f..a0573c52193 100644 --- a/drivers/misc/rockchip-io-domain.c +++ b/drivers/misc/rockchip-io-domain.c @@ -344,8 +344,10 @@ static int rockchip_iodomain_probe(struct udevice *dev) continue; ret = device_get_supply_regulator(dev, supply_name, ®); - if (ret) + if (ret) { + dev_dbg(dev, "%s: Regulator not found\n", supply_name); continue; + } ret = regulator_autoset(reg); if (ret && ret != -EALREADY && ret != -EMEDIUMTYPE && @@ -353,6 +355,7 @@ static int rockchip_iodomain_probe(struct udevice *dev) continue; uV = regulator_get_value(reg); + dev_dbg(dev, "%s: Regulator %s at %d uV\n", supply_name, reg->name, uV); if (uV <= 0) continue; diff --git a/drivers/misc/stm32_rcc.c b/drivers/misc/stm32_rcc.c index 5a6f979f91b..15bf69f7d57 100644 --- a/drivers/misc/stm32_rcc.c +++ b/drivers/misc/stm32_rcc.c @@ -14,47 +14,56 @@ #include <dm/device_compat.h> #include <dm/lists.h> -struct stm32_rcc_clk stm32_rcc_clk_f42x = { - .drv_name = "stm32fx_rcc_clock", +static const struct stm32_rcc stm32_rcc_f42x = { + .drv_name_clk = "stm32fx_rcc_clock", + .drv_name_rst = "stm32_rcc_reset", .soc = STM32F42X, }; -struct stm32_rcc_clk stm32_rcc_clk_f469 = { - .drv_name = "stm32fx_rcc_clock", +static const struct stm32_rcc stm32_rcc_f469 = { + .drv_name_clk = "stm32fx_rcc_clock", + .drv_name_rst = "stm32_rcc_reset", .soc = STM32F469, }; -struct stm32_rcc_clk stm32_rcc_clk_f7 = { - .drv_name = "stm32fx_rcc_clock", +static const struct stm32_rcc stm32_rcc_f7 = { + .drv_name_clk = "stm32fx_rcc_clock", + .drv_name_rst = "stm32_rcc_reset", .soc = STM32F7, }; -struct stm32_rcc_clk stm32_rcc_clk_h7 = { - .drv_name = "stm32h7_rcc_clock", +static const struct stm32_rcc stm32_rcc_h7 = { + .drv_name_clk = "stm32h7_rcc_clock", + .drv_name_rst = "stm32_rcc_reset", }; -struct stm32_rcc_clk stm32_rcc_clk_mp1 = { - .drv_name = "stm32mp1_clk", - .soc = STM32MP1, +static const struct stm32_rcc stm32_rcc_mp15 = { + .drv_name_clk = "stm32mp1_clk", + .drv_name_rst = "stm32mp1_reset", }; -struct stm32_rcc_clk stm32_rcc_clk_mp13 = { - .drv_name = "stm32mp13_clk", - .soc = STM32MP1, +static const struct stm32_rcc stm32_rcc_mp13 = { + .drv_name_clk = "stm32mp13_clk", + .drv_name_rst = "stm32mp1_reset", +}; + +static const struct stm32_rcc stm32_rcc_mp25 = { + .drv_name_clk = "stm32mp25_clk", + .drv_name_rst = "stm32mp25_reset", }; static int stm32_rcc_bind(struct udevice *dev) { struct udevice *child; struct driver *drv; - struct stm32_rcc_clk *rcc_clk = - (struct stm32_rcc_clk *)dev_get_driver_data(dev); + struct stm32_rcc *rcc_clk = + (struct stm32_rcc *)dev_get_driver_data(dev); int ret; dev_dbg(dev, "RCC bind\n"); - drv = lists_driver_lookup_name(rcc_clk->drv_name); + drv = lists_driver_lookup_name(rcc_clk->drv_name_clk); if (!drv) { - dev_err(dev, "Cannot find driver '%s'\n", rcc_clk->drv_name); + dev_err(dev, "Cannot find driver '%s'\n", rcc_clk->drv_name_clk); return -ENOENT; } @@ -65,25 +74,24 @@ static int stm32_rcc_bind(struct udevice *dev) if (ret) return ret; - drv = lists_driver_lookup_name("stm32_rcc_reset"); + drv = lists_driver_lookup_name(rcc_clk->drv_name_rst); if (!drv) { dev_err(dev, "Cannot find driver stm32_rcc_reset'\n"); return -ENOENT; } - return device_bind_with_driver_data(dev, drv, dev->name, - rcc_clk->soc, - dev_ofnode(dev), &child); + return device_bind(dev, drv, dev->name, NULL, dev_ofnode(dev), &child); } static const struct udevice_id stm32_rcc_ids[] = { - {.compatible = "st,stm32f42xx-rcc", .data = (ulong)&stm32_rcc_clk_f42x }, - {.compatible = "st,stm32f469-rcc", .data = (ulong)&stm32_rcc_clk_f469 }, - {.compatible = "st,stm32f746-rcc", .data = (ulong)&stm32_rcc_clk_f7 }, - {.compatible = "st,stm32h743-rcc", .data = (ulong)&stm32_rcc_clk_h7 }, - {.compatible = "st,stm32mp1-rcc", .data = (ulong)&stm32_rcc_clk_mp1 }, - {.compatible = "st,stm32mp1-rcc-secure", .data = (ulong)&stm32_rcc_clk_mp1 }, - {.compatible = "st,stm32mp13-rcc", .data = (ulong)&stm32_rcc_clk_mp13 }, + {.compatible = "st,stm32f42xx-rcc", .data = (ulong)&stm32_rcc_f42x }, + {.compatible = "st,stm32f469-rcc", .data = (ulong)&stm32_rcc_f469 }, + {.compatible = "st,stm32f746-rcc", .data = (ulong)&stm32_rcc_f7 }, + {.compatible = "st,stm32h743-rcc", .data = (ulong)&stm32_rcc_h7 }, + {.compatible = "st,stm32mp1-rcc", .data = (ulong)&stm32_rcc_mp15 }, + {.compatible = "st,stm32mp1-rcc-secure", .data = (ulong)&stm32_rcc_mp15 }, + {.compatible = "st,stm32mp13-rcc", .data = (ulong)&stm32_rcc_mp13 }, + {.compatible = "st,stm32mp25-rcc", .data = (ulong)&stm32_rcc_mp25 }, { } }; diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 38867f30a7e..1c9b6898bff 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -528,7 +528,7 @@ config SPL_MMC_SDHCI_ADMA config MMC_SDHCI_ADMA_FORCE_32BIT bool "Force 32 bit mode for ADMA on 64 bit platforms" - depends on MMC_SDHCI_ADMA || SPL_MMC_SDHCI_ADMA + depends on MMC_SDHCI_ADMA_HELPERS help This forces SDHCI ADMA to be built for 32 bit descriptors, even on a 64 bit platform where they would otherwise be assumed to @@ -538,7 +538,7 @@ config MMC_SDHCI_ADMA_FORCE_32BIT config MMC_SDHCI_ADMA_64BIT bool "Use SHDCI ADMA with 64 bit descriptors" - depends on MMC_SDHCI_ADMA || SPL_MMC_SDHCI_ADMA + depends on MMC_SDHCI_ADMA_HELPERS depends on !MMC_SDHCI_ADMA_FORCE_32BIT default y if DMA_ADDR_T_64BIT help diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c index 0df3568f073..d3c8f94dd0c 100644 --- a/drivers/mmc/am654_sdhci.c +++ b/drivers/mmc/am654_sdhci.c @@ -527,11 +527,16 @@ static int am654_sdhci_execute_tuning(struct mmc *mmc, u8 opcode) void am654_sdhci_set_control_reg(struct sdhci_host *host) { struct mmc *mmc = host->mmc; + u32 reg; + reg = sdhci_readw(host, SDHCI_HOST_CONTROL2); + reg &= ~SDHCI_CTRL_UHS_MASK; sdhci_set_voltage(host); if (mmc->selected_mode > MMC_HS_52) sdhci_set_uhs_timing(host); + else + sdhci_writew(host, reg, SDHCI_HOST_CONTROL2); } const struct sdhci_ops am654_sdhci_ops = { diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 9421a846e45..2c1f4f9c336 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -3278,8 +3278,8 @@ int mmc_set_bkops_enable(struct mmc *mmc, bool autobkops, bool enable) __weak int mmc_get_env_dev(void) { -#ifdef CONFIG_SYS_MMC_ENV_DEV - return CONFIG_SYS_MMC_ENV_DEV; +#ifdef CONFIG_ENV_MMC_DEVICE_INDEX + return CONFIG_ENV_MMC_DEVICE_INDEX; #else return 0; #endif diff --git a/drivers/mmc/sdhci-cadence6.c b/drivers/mmc/sdhci-cadence6.c index a5ed87321ab..9a92b8437a6 100644 --- a/drivers/mmc/sdhci-cadence6.c +++ b/drivers/mmc/sdhci-cadence6.c @@ -19,7 +19,7 @@ #include "sdhci-cadence.h" /* IO Delay Information */ -#define SDHCI_CDNS_HRS07 0X1C +#define SDHCI_CDNS_HRS07 0x1C #define SDHCI_CDNS_HRS07_RW_COMPENSATE GENMASK(20, 16) #define SDHCI_CDNS_HRS07_IDELAY_VAL GENMASK(4, 0) diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 0e2bdab4e7e..2375b15539b 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -83,7 +83,7 @@ #define VERSAL_NET_EMMC_ICLK_PHASE_DDR52_DLY_CHAIN 39 #define VERSAL_NET_EMMC_ICLK_PHASE_DDR52_DLL 146 -#define VERSAL_NET_PHY_CTRL_STRB90_STRB180_VAL 0X77 +#define VERSAL_NET_PHY_CTRL_STRB90_STRB180_VAL 0x77 struct arasan_sdhci_clk_data { int clk_phase_in[MMC_TIMING_MMC_HS400 + 1]; diff --git a/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c b/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c index 4430c4e93ee..7779e63fa5d 100644 --- a/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c +++ b/drivers/mtd/nand/raw/lpc32xx_nand_mlc.c @@ -165,9 +165,9 @@ static void lpc32xx_cmd_ctrl(struct mtd_info *mtd, int cmd, return; if (ctrl & NAND_CLE) - writeb(cmd & 0Xff, &lpc32xx_nand_mlc_registers->cmd); + writeb(cmd & 0xff, &lpc32xx_nand_mlc_registers->cmd); else if (ctrl & NAND_ALE) - writeb(cmd & 0Xff, &lpc32xx_nand_mlc_registers->addr); + writeb(cmd & 0xff, &lpc32xx_nand_mlc_registers->addr); } /** diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c index dd4ed257a83..16abf89dbbf 100644 --- a/drivers/mtd/nand/spi/winbond.c +++ b/drivers/mtd/nand/spi/winbond.c @@ -11,6 +11,7 @@ #include <linux/device.h> #include <linux/kernel.h> #endif +#include <linux/bitfield.h> #include <linux/bug.h> #include <linux/mtd/spinand.h> @@ -18,6 +19,8 @@ #define WINBOND_CFG_BUF_READ BIT(3) +#define W25N04KV_STATUS_ECC_5_8_BITFLIPS FIELD_PREP_CONST(STATUS_ECC_MASK, 0x3) + static SPINAND_OP_VARIANTS(read_cache_variants, SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), @@ -121,6 +124,7 @@ static int w25n02kv_ecc_get_status(struct spinand_device *spinand, return -EBADMSG; case STATUS_ECC_HAS_BITFLIPS: + case W25N04KV_STATUS_ECC_5_8_BITFLIPS: /* * Let's try to retrieve the real maximum number of bitflips * in order to avoid forcing the wear-leveling layer to move @@ -172,6 +176,15 @@ static const struct spinand_info winbond_spinand_table[] = { &update_cache_variants), 0, SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), + SPINAND_INFO("W25N04KV", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x23), + NAND_MEMORG(1, 2048, 128, 64, 4096, 40, 2, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), }; static int winbond_spinand_init(struct spinand_device *spinand) diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 0f93c25e3fe..fce3ef910cb 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -716,7 +716,7 @@ static int _dw_free_pkt(struct dw_eth_dev *priv) ulong desc_start = (ulong)desc_p; ulong desc_end = desc_start + roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN); - ulong data_start = desc_p->dmamac_addr; + ulong data_start = dev_bus_to_phys(priv->dev, desc_p->dmamac_addr); ulong data_end = data_start + roundup(CFG_ETH_BUFSIZE, ARCH_DMA_MINALIGN); /* Invalidate the descriptor buffer data */ diff --git a/drivers/net/fm/fm.c b/drivers/net/fm/fm.c index a8caa0f0927..146f3f1fbd3 100644 --- a/drivers/net/fm/fm.c +++ b/drivers/net/fm/fm.c @@ -410,12 +410,12 @@ int fm_init_common(int index, struct ccsr_fman *reg, const char *firmware_name) spi_flash_free(ucode_flash); } } else if (src == BOOT_SOURCE_SD_MMC) { - int dev = CONFIG_SYS_MMC_ENV_DEV; + int dev = CONFIG_ENV_MMC_DEVICE_INDEX; addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH); u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512; u32 blk = CONFIG_SYS_FMAN_FW_ADDR / 512; - struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV); + struct mmc *mmc = find_mmc_device(CONFIG_ENV_MMC_DEVICE_INDEX); if (!mmc) { printf("\nMMC cannot find device for ucode\n"); @@ -514,11 +514,11 @@ int fm_init_common(int index, struct ccsr_fman *reg, const char *firmware_name) spi_flash_free(ucode_flash); } #elif defined(CONFIG_SYS_QE_FMAN_FW_IN_MMC) - int dev = CONFIG_SYS_MMC_ENV_DEV; + int dev = CONFIG_ENV_MMC_DEVICE_INDEX; void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH); u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512; u32 blk = CONFIG_SYS_FMAN_FW_ADDR / 512; - struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV); + struct mmc *mmc = find_mmc_device(CONFIG_ENV_MMC_DEVICE_INDEX); if (!mmc) printf("\nMMC cannot find device for ucode\n"); diff --git a/drivers/net/fsl-mc/mc.c b/drivers/net/fsl-mc/mc.c index c2869ce4010..86daf0fb2bb 100644 --- a/drivers/net/fsl-mc/mc.c +++ b/drivers/net/fsl-mc/mc.c @@ -45,7 +45,7 @@ #define MC_BUFFER_SIZE (1024 * 1024 * 16) #define MAGIC_MC 0x4d430100 #define MC_FW_ADDR_MASK_LOW 0xE0000000 -#define MC_FW_ADDR_MASK_HIGH 0X1FFFF +#define MC_FW_ADDR_MASK_HIGH 0x1FFFF #define MC_STRUCT_BUFFER_OFFSET 0x01000000 #define MC_OFFSET_DELTA MC_STRUCT_BUFFER_OFFSET diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c index ae545fe229c..184c1f9a46a 100644 --- a/drivers/net/mvpp2.c +++ b/drivers/net/mvpp2.c @@ -3876,7 +3876,6 @@ mvpp2_rxq_next_desc_get(struct mvpp2_rx_queue *rxq) int rx_desc = rxq->next_desc_to_proc; rxq->next_desc_to_proc = MVPP2_QUEUE_NEXT_DESC(rxq, rx_desc); - prefetch(rxq->descs + rxq->next_desc_to_proc); return rxq->descs + rx_desc; } diff --git a/drivers/net/octeontx/nicvf_main.c b/drivers/net/octeontx/nicvf_main.c index 6e4d0a05121..27d0327c88a 100644 --- a/drivers/net/octeontx/nicvf_main.c +++ b/drivers/net/octeontx/nicvf_main.c @@ -279,8 +279,6 @@ int nicvf_cq_handler(struct nicvf *nic, void **ppkt, int *pkt_len) cq_desc = (struct cqe_rx_t *)GET_CQ_DESC(cq, cqe_head); cqe_head++; cqe_head &= (cq->dmem.q_len - 1); - /* Initiate prefetch for next descriptor */ - prefetch((struct cqe_rx_t *)GET_CQ_DESC(cq, cqe_head)); switch (cq_desc->cqe_type) { case CQE_TYPE_RX: diff --git a/drivers/net/phy/ca_phy.c b/drivers/net/phy/ca_phy.c index 5b2c67d2fda..72d370274a1 100644 --- a/drivers/net/phy/ca_phy.c +++ b/drivers/net/phy/ca_phy.c @@ -73,7 +73,7 @@ static void __external_phy_init(struct phy_device *phydev, int reset_phy) val &= ~(1 << 2); phy_write(phydev, MDIO_DEVAD_NONE, 27, val); - /* REG31 write 0X0000, back to page0 */ + /* REG31 write 0x0000, back to page0 */ phy_write(phydev, MDIO_DEVAD_NONE, 31, 0x0000); } diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c index d043e859bad..be480ecef6c 100644 --- a/drivers/net/phy/cortina.c +++ b/drivers/net/phy/cortina.c @@ -170,10 +170,10 @@ void cs4340_upload_firmware(struct phy_device *phydev) spi_flash_free(ucode_flash); } } else if (src == BOOT_SOURCE_SD_MMC) { - int dev = CONFIG_SYS_MMC_ENV_DEV; + int dev = CONFIG_ENV_MMC_DEVICE_INDEX; u32 cnt = CONFIG_CORTINA_FW_LENGTH / 512; u32 blk = cortina_fw_addr / 512; - struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV); + struct mmc *mmc = find_mmc_device(CONFIG_ENV_MMC_DEVICE_INDEX); if (!mmc) { puts("Failed to find MMC device for Cortina ucode\n"); @@ -223,10 +223,10 @@ void cs4340_upload_firmware(struct phy_device *phydev) spi_flash_free(ucode_flash); } #elif defined(CONFIG_SYS_CORTINA_FW_IN_MMC) - int dev = CONFIG_SYS_MMC_ENV_DEV; + int dev = CONFIG_ENV_MMC_DEVICE_INDEX; u32 cnt = CONFIG_CORTINA_FW_LENGTH / 512; u32 blk = cortina_fw_addr / 512; - struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV); + struct mmc *mmc = find_mmc_device(CONFIG_ENV_MMC_DEVICE_INDEX); if (!mmc) { puts("Failed to find MMC device for Cortina ucode\n"); diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 461805ae53f..703e22479d2 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -567,12 +567,14 @@ static int zynq_gem_init(struct udevice *dev) } #endif - ret = clk_get_rate(&priv->tx_clk); - if (ret != clk_rate) { - ret = clk_set_rate(&priv->tx_clk, clk_rate); - if (IS_ERR_VALUE(ret)) { - dev_err(dev, "failed to set tx clock rate %ld\n", clk_rate); - return ret; + if (priv->interface != PHY_INTERFACE_MODE_MII) { + ret = clk_get_rate(&priv->tx_clk); + if (ret != clk_rate) { + ret = clk_set_rate(&priv->tx_clk, clk_rate); + if (IS_ERR_VALUE(ret)) { + dev_err(dev, "failed to set tx clock rate %ld\n", clk_rate); + return ret; + } } } diff --git a/drivers/pci/pcie-xilinx-nwl.c b/drivers/pci/pcie-xilinx-nwl.c index 7ef2bdf57b5..e03ab3be912 100644 --- a/drivers/pci/pcie-xilinx-nwl.c +++ b/drivers/pci/pcie-xilinx-nwl.c @@ -303,6 +303,13 @@ static int nwl_pcie_parse_dt(struct nwl_pcie *pcie) return PTR_ERR(pcie->breg_base); pcie->phys_breg_base = res.start; + ret = dev_read_resource_byname(dev, "pcireg", &res); + if (ret) + return ret; + pcie->pcireg_base = devm_ioremap(dev, res.start, resource_size(&res)); + if (IS_ERR(pcie->pcireg_base)) + return PTR_ERR(pcie->pcireg_base); + ret = dev_read_resource_byname(dev, "cfg", &res); if (ret) return ret; diff --git a/drivers/phy/phy-stm32-usbphyc.c b/drivers/phy/phy-stm32-usbphyc.c index 8d643b762f9..fcf8617ee9b 100644 --- a/drivers/phy/phy-stm32-usbphyc.c +++ b/drivers/phy/phy-stm32-usbphyc.c @@ -16,7 +16,9 @@ #include <syscon.h> #include <usb.h> #include <asm/io.h> +#include <dm/device.h> #include <dm/device_compat.h> +#include <dm/device-internal.h> #include <dm/lists.h> #include <dm/of_access.h> #include <linux/bitfield.h> @@ -633,6 +635,7 @@ U_BOOT_DRIVER(stm32_usb_phyc) = { struct stm32_usbphyc_clk { bool enable; + struct clk clkp; }; static ulong stm32_usbphyc_clk48_get_rate(struct clk *clk) @@ -687,9 +690,25 @@ const struct clk_ops usbphyc_clk48_ops = { .disable = stm32_usbphyc_clk48_disable, }; +int usbphyc_clk48_probe(struct udevice *dev) +{ + struct stm32_usbphyc_clk *priv = dev_get_priv(dev); + + /* prepare clkp to correctly register clock with CCF */ + priv->clkp.dev = dev; + priv->clkp.id = CLK_ID(dev, 0); + + /* Store back pointer to clk from udevice */ + /* FIXME: This is not allowed...should be allocated by driver model */ + dev_set_uclass_priv(dev, &priv->clkp); + + return 0; +} + U_BOOT_DRIVER(stm32_usb_phyc_clk) = { .name = "stm32-usbphyc-clk", .id = UCLASS_CLK, .ops = &usbphyc_clk48_ops, + .probe = &usbphyc_clk48_probe, .priv_auto = sizeof(struct stm32_usbphyc_clk), }; diff --git a/drivers/phy/phy-zynqmp.c b/drivers/phy/phy-zynqmp.c index 7049e740d56..9649e660220 100644 --- a/drivers/phy/phy-zynqmp.c +++ b/drivers/phy/phy-zynqmp.c @@ -138,6 +138,7 @@ #define PROT_BUS_WIDTH_40 0x2 #define PROT_BUS_WIDTH_MASK 0x3 #define PROT_BUS_WIDTH_SHIFT 2 +#define GEM_CLK_CTRL_WIDTH_SHIFT 5 /* Number of GT lanes */ #define NUM_LANES 4 @@ -400,6 +401,7 @@ static void xpsgtr_phy_init_sgmii(struct xpsgtr_phy *gtr_phy) { struct xpsgtr_dev *gtr_dev = gtr_phy->dev; u32 shift = gtr_phy->lane * PROT_BUS_WIDTH_SHIFT; + u32 clk_ctrl_shift = gtr_phy->lane * GEM_CLK_CTRL_WIDTH_SHIFT; /* Set SGMII protocol TX and RX bus width to 10 bits. */ xpsgtr_clr_set(gtr_dev, TX_PROT_BUS_WIDTH, PROT_BUS_WIDTH_MASK << shift, @@ -417,9 +419,9 @@ static void xpsgtr_phy_init_sgmii(struct xpsgtr_phy *gtr_phy) */ /* GEM I/O Clock Control */ clrsetbits_le32(ZYNQMP_IOU_SLCR_BASEADDR + IOU_SLCR_GEM_CLK_CTRL, - 0xf << shift, + 0xf << clk_ctrl_shift, (GEM_CTRL_GEM_SGMII_MODE | GEM_CTRL_GEM_REF_SRC_SEL) << - shift); + clk_ctrl_shift); /* Setup signal detect */ clrsetbits_le32(ZYNQMP_IOU_SLCR_BASEADDR + IOU_SLCR_GEM_CTRL, diff --git a/drivers/phy/qcom/phy-qcom-qmp-ufs.c b/drivers/phy/qcom/phy-qcom-qmp-ufs.c index 449b9767778..f3c606847fb 100644 --- a/drivers/phy/qcom/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qcom/phy-qcom-qmp-ufs.c @@ -86,6 +86,12 @@ enum qphy_reg_layout { QPHY_LAYOUT_SIZE }; +static const unsigned int ufsphy_v2_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_START_CTRL] = QPHY_V2_PCS_UFS_PHY_START, + [QPHY_PCS_READY_STATUS] = QPHY_V2_PCS_UFS_READY_STATUS, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V2_PCS_UFS_POWER_DOWN_CONTROL, +}; + static const unsigned int ufsphy_v3_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_START_CTRL] = QPHY_V3_PCS_UFS_PHY_START, [QPHY_PCS_READY_STATUS] = QPHY_V3_PCS_UFS_READY_STATUS, @@ -715,6 +721,98 @@ static const struct qmp_ufs_init_tbl sc7280_ufsphy_hs_g4_rx[] = { QMP_PHY_INIT_CFG(QSERDES_V4_RX_GM_CAL, 0x0f), }; +static const struct qmp_ufs_init_tbl sm6115_ufsphy_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14), + QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x02), + QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), + QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV_MODE1, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x01), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER1, 0xff), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER2, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x04), + QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0xff), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE1, 0x98), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE1, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE1, 0x28), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x80), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE1, 0xd6), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE1, 0x32), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE1, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_INITVAL1, 0xff), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_INITVAL2, 0x00), +}; + +static const struct qmp_ufs_init_tbl sm6115_ufsphy_hs_b_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x44), +}; + +static const struct qmp_ufs_init_tbl sm6115_ufsphy_tx[] = { + QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45), + QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x06), +}; + +static const struct qmp_ufs_init_tbl sm6115_ufsphy_rx[] = { + QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_LVL, 0x24), + QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_CNTRL, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_INTERFACE_MODE, 0x40), + QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x1e), + QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_TERM_BW, 0x5b), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN1_LSB, 0xff), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN1_MSB, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN2_LSB, 0xff), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN2_MSB, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SVS_SO_GAIN_HALF, 0x04), + QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04), + QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SVS_SO_GAIN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x5b), +}; + +static const struct qmp_ufs_init_tbl sm6115_ufsphy_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_RX_PWM_GEAR_BAND, 0x15), + QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_RX_SIGDET_CTRL2, 0x6d), + QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f), + QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_TX_SMALL_AMP_DRV_LVL, 0x02), + QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_RX_MIN_STALL_NOCONFIG_TIME_CAP, 0x28), + QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_RX_SYM_RESYNC_CTRL, 0x03), + QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_TX_LARGE_AMP_POST_EMP_LVL, 0x12), + QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_TX_SMALL_AMP_POST_EMP_LVL, 0x0f), + QMP_PHY_INIT_CFG(QPHY_V2_PCS_UFS_RX_MIN_HIBERN8_TIME, 0x9a), /* 8 us */ +}; + struct qmp_ufs_offsets { u16 serdes; u16 pcs; @@ -1079,6 +1177,34 @@ static const struct qmp_ufs_cfg sa8775p_ufsphy_cfg = { .regs = ufsphy_v5_regs_layout, }; +static const struct qmp_ufs_cfg sm6115_ufsphy_cfg = { + .lanes = 1, + + .offsets = &qmp_ufs_offsets, + + .tbls = { + .serdes = sm6115_ufsphy_serdes, + .serdes_num = ARRAY_SIZE(sm6115_ufsphy_serdes), + .tx = sm6115_ufsphy_tx, + .tx_num = ARRAY_SIZE(sm6115_ufsphy_tx), + .rx = sm6115_ufsphy_rx, + .rx_num = ARRAY_SIZE(sm6115_ufsphy_rx), + .pcs = sm6115_ufsphy_pcs, + .pcs_num = ARRAY_SIZE(sm6115_ufsphy_pcs), + }, + .tbls_hs_b = { + .serdes = sm6115_ufsphy_hs_b_serdes, + .serdes_num = ARRAY_SIZE(sm6115_ufsphy_hs_b_serdes), + }, + .clk_list = sdm845_ufs_phy_clk_l, + .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), + .vreg_list = qmp_ufs_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_ufs_vreg_l), + .regs = ufsphy_v2_regs_layout, + + .no_pcs_sw_reset = true, +}; + static void qmp_ufs_configure_lane(void __iomem *base, const struct qmp_ufs_init_tbl tbl[], int num, @@ -1469,9 +1595,11 @@ static const struct udevice_id qmp_ufs_ids[] = { { .compatible = "qcom,sdm845-qmp-ufs-phy", .data = (ulong)&sdm845_ufsphy_cfg }, { .compatible = "qcom,sm8150-qmp-ufs-phy", .data = (ulong)&sm8150_ufsphy_cfg }, { .compatible = "qcom,sm8250-qmp-ufs-phy", .data = (ulong)&sm8250_ufsphy_cfg }, + { .compatible = "qcom,qcs8300-qmp-ufs-phy", .data = (ulong)&sa8775p_ufsphy_cfg }, { .compatible = "qcom,sm8550-qmp-ufs-phy", .data = (ulong)&sm8550_ufsphy_cfg }, { .compatible = "qcom,sm8650-qmp-ufs-phy", .data = (ulong)&sm8650_ufsphy_cfg }, { .compatible = "qcom,sc7280-qmp-ufs-phy", .data = (ulong)&sc7280_ufsphy_cfg, }, + { .compatible = "qcom,qcs615-qmp-ufs-phy", .data = (ulong)&sm6115_ufsphy_cfg, }, { } }; diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index c7459dbc5fc..c48a5cd5267 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -284,7 +284,7 @@ DECLARE_GLOBAL_DATA_PTR; * clock 0: PLL 0 div 1 * clock 1: PLL 1 div 2 */ -#define CLK_PLL_CONFIG 0X30 +#define CLK_PLL_CONFIG 0x30 #define CLK_PLL_MASK 0x33 #define CMN_READY BIT(0) diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index e567cb113a3..21f81b66099 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -27,6 +27,13 @@ config PINCTRL_QCOM_IPQ4019 Say Y here to enable support for pinctrl on the IPQ4019 SoC, as well as the associated GPIO driver. +config PINCTRL_QCOM_IPQ5424 + bool "Qualcomm IPQ5424 Pinctrl" + select PINCTRL_QCOM + help + Say Y here to enable support for pinctrl on the IPQ5424 SoC, + as well as the associated GPIO driver. + config PINCTRL_QCOM_IPQ9574 bool "Qualcomm IPQ9574 Pinctrl" select PINCTRL_QCOM diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 6ffc6d48c15..6cb53838e71 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_PINCTRL_QCOM) += pinctrl-qcom.o obj-$(CONFIG_PINCTRL_QCOM_APQ8016) += pinctrl-apq8016.o obj-$(CONFIG_PINCTRL_QCOM_IPQ4019) += pinctrl-ipq4019.o +obj-$(CONFIG_PINCTRL_QCOM_IPQ5424) += pinctrl-ipq5424.o obj-$(CONFIG_PINCTRL_QCOM_IPQ9574) += pinctrl-ipq9574.o obj-$(CONFIG_PINCTRL_QCOM_APQ8096) += pinctrl-apq8096.o obj-$(CONFIG_PINCTRL_QCOM_QCM2290) += pinctrl-qcm2290.o diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5424.c b/drivers/pinctrl/qcom/pinctrl-ipq5424.c new file mode 100644 index 00000000000..cde990a32ef --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-ipq5424.c @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2016-2018,2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include <dm.h> + +#include "pinctrl-qcom.h" + +#define MAX_PIN_NAME_LEN 32 +static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); + +enum ipq5424_functions { + msm_mux_atest_char, + msm_mux_atest_char0, + msm_mux_atest_char1, + msm_mux_atest_char2, + msm_mux_atest_char3, + msm_mux_atest_tic, + msm_mux_audio_pri, + msm_mux_audio_pri0, + msm_mux_audio_pri1, + msm_mux_audio_sec, + msm_mux_audio_sec0, + msm_mux_audio_sec1, + msm_mux_core_voltage, + msm_mux_cri_trng0, + msm_mux_cri_trng1, + msm_mux_cri_trng2, + msm_mux_cri_trng3, + msm_mux_cxc_clk, + msm_mux_cxc_data, + msm_mux_dbg_out, + msm_mux_gcc_plltest, + msm_mux_gcc_tlmm, + msm_mux_gpio, + msm_mux_i2c0_scl, + msm_mux_i2c0_sda, + msm_mux_i2c1_scl, + msm_mux_i2c1_sda, + msm_mux_i2c11, + msm_mux_mac0, + msm_mux_mac1, + msm_mux_mdc_mst, + msm_mux_mdc_slv, + msm_mux_mdio_mst, + msm_mux_mdio_slv, + msm_mux_pcie0_clk, + msm_mux_pcie0_wake, + msm_mux_pcie1_clk, + msm_mux_pcie1_wake, + msm_mux_pcie2_clk, + msm_mux_pcie2_wake, + msm_mux_pcie3_clk, + msm_mux_pcie3_wake, + msm_mux_pll_test, + msm_mux_prng_rosc0, + msm_mux_prng_rosc1, + msm_mux_prng_rosc2, + msm_mux_prng_rosc3, + msm_mux_PTA0_0, + msm_mux_PTA0_1, + msm_mux_PTA0_2, + msm_mux_PTA10, + msm_mux_PTA11, + msm_mux_pwm0, + msm_mux_pwm1, + msm_mux_pwm2, + msm_mux_qdss_cti_trig_in_a0, + msm_mux_qdss_cti_trig_out_a0, + msm_mux_qdss_cti_trig_in_a1, + msm_mux_qdss_cti_trig_out_a1, + msm_mux_qdss_cti_trig_in_b0, + msm_mux_qdss_cti_trig_out_b0, + msm_mux_qdss_cti_trig_in_b1, + msm_mux_qdss_cti_trig_out_b1, + msm_mux_qdss_traceclk_a, + msm_mux_qdss_tracectl_a, + msm_mux_qdss_tracedata_a, + msm_mux_qspi_clk, + msm_mux_qspi_cs, + msm_mux_qspi_data, + msm_mux_resout, + msm_mux_rx0, + msm_mux_rx1, + msm_mux_rx2, + msm_mux_sdc_clk, + msm_mux_sdc_cmd, + msm_mux_sdc_data, + msm_mux_spi0_clk, + msm_mux_spi0_cs, + msm_mux_spi0_miso, + msm_mux_spi0_mosi, + msm_mux_spi1, + msm_mux_spi10, + msm_mux_spi11, + msm_mux_tsens_max, + msm_mux_uart0, + msm_mux_uart1, + msm_mux_wci_txd, + msm_mux_wci_rxd, + msm_mux_wsi_clk, + msm_mux_wsi_data, + msm_mux__, +}; + +#define MSM_PIN_FUNCTION(fname) \ + [msm_mux_##fname] = {#fname, msm_mux_##fname} + +static const struct pinctrl_function ipq5424_functions[] = { + MSM_PIN_FUNCTION(atest_char), + MSM_PIN_FUNCTION(atest_char0), + MSM_PIN_FUNCTION(atest_char1), + MSM_PIN_FUNCTION(atest_char2), + MSM_PIN_FUNCTION(atest_char3), + MSM_PIN_FUNCTION(atest_tic), + MSM_PIN_FUNCTION(audio_pri), + MSM_PIN_FUNCTION(audio_pri0), + MSM_PIN_FUNCTION(audio_pri1), + MSM_PIN_FUNCTION(audio_sec), + MSM_PIN_FUNCTION(audio_sec0), + MSM_PIN_FUNCTION(audio_sec1), + MSM_PIN_FUNCTION(core_voltage), + MSM_PIN_FUNCTION(cri_trng0), + MSM_PIN_FUNCTION(cri_trng1), + MSM_PIN_FUNCTION(cri_trng2), + MSM_PIN_FUNCTION(cri_trng3), + MSM_PIN_FUNCTION(cxc_clk), + MSM_PIN_FUNCTION(cxc_data), + MSM_PIN_FUNCTION(dbg_out), + MSM_PIN_FUNCTION(gcc_plltest), + MSM_PIN_FUNCTION(gcc_tlmm), + MSM_PIN_FUNCTION(gpio), + MSM_PIN_FUNCTION(i2c0_scl), + MSM_PIN_FUNCTION(i2c0_sda), + MSM_PIN_FUNCTION(i2c1_scl), + MSM_PIN_FUNCTION(i2c1_sda), + MSM_PIN_FUNCTION(i2c11), + MSM_PIN_FUNCTION(mac0), + MSM_PIN_FUNCTION(mac1), + MSM_PIN_FUNCTION(mdc_mst), + MSM_PIN_FUNCTION(mdc_slv), + MSM_PIN_FUNCTION(mdio_mst), + MSM_PIN_FUNCTION(mdio_slv), + MSM_PIN_FUNCTION(pcie0_clk), + MSM_PIN_FUNCTION(pcie0_wake), + MSM_PIN_FUNCTION(pcie1_clk), + MSM_PIN_FUNCTION(pcie1_wake), + MSM_PIN_FUNCTION(pcie2_clk), + MSM_PIN_FUNCTION(pcie2_wake), + MSM_PIN_FUNCTION(pcie3_clk), + MSM_PIN_FUNCTION(pcie3_wake), + MSM_PIN_FUNCTION(pll_test), + MSM_PIN_FUNCTION(prng_rosc0), + MSM_PIN_FUNCTION(prng_rosc1), + MSM_PIN_FUNCTION(prng_rosc2), + MSM_PIN_FUNCTION(prng_rosc3), + MSM_PIN_FUNCTION(PTA0_0), + MSM_PIN_FUNCTION(PTA0_1), + MSM_PIN_FUNCTION(PTA0_2), + MSM_PIN_FUNCTION(PTA10), + MSM_PIN_FUNCTION(PTA11), + MSM_PIN_FUNCTION(pwm0), + MSM_PIN_FUNCTION(pwm1), + MSM_PIN_FUNCTION(pwm2), + MSM_PIN_FUNCTION(qdss_cti_trig_in_a0), + MSM_PIN_FUNCTION(qdss_cti_trig_out_a0), + MSM_PIN_FUNCTION(qdss_cti_trig_in_a1), + MSM_PIN_FUNCTION(qdss_cti_trig_out_a1), + MSM_PIN_FUNCTION(qdss_cti_trig_in_b0), + MSM_PIN_FUNCTION(qdss_cti_trig_out_b0), + MSM_PIN_FUNCTION(qdss_cti_trig_in_b1), + MSM_PIN_FUNCTION(qdss_cti_trig_out_b1), + MSM_PIN_FUNCTION(qdss_traceclk_a), + MSM_PIN_FUNCTION(qdss_tracectl_a), + MSM_PIN_FUNCTION(qdss_tracedata_a), + MSM_PIN_FUNCTION(qspi_clk), + MSM_PIN_FUNCTION(qspi_cs), + MSM_PIN_FUNCTION(qspi_data), + MSM_PIN_FUNCTION(resout), + MSM_PIN_FUNCTION(rx0), + MSM_PIN_FUNCTION(rx1), + MSM_PIN_FUNCTION(rx2), + MSM_PIN_FUNCTION(sdc_clk), + MSM_PIN_FUNCTION(sdc_cmd), + MSM_PIN_FUNCTION(sdc_data), + MSM_PIN_FUNCTION(spi0_clk), + MSM_PIN_FUNCTION(spi0_cs), + MSM_PIN_FUNCTION(spi0_miso), + MSM_PIN_FUNCTION(spi0_mosi), + MSM_PIN_FUNCTION(spi1), + MSM_PIN_FUNCTION(spi10), + MSM_PIN_FUNCTION(spi11), + MSM_PIN_FUNCTION(tsens_max), + MSM_PIN_FUNCTION(uart0), + MSM_PIN_FUNCTION(uart1), + MSM_PIN_FUNCTION(wci_txd), + MSM_PIN_FUNCTION(wci_rxd), + MSM_PIN_FUNCTION(wsi_clk), + MSM_PIN_FUNCTION(wsi_data), +}; + +typedef unsigned int msm_pin_function[10]; + +#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9)\ + [id] = { msm_mux_gpio, /* gpio mode */ \ + msm_mux_##f1, \ + msm_mux_##f2, \ + msm_mux_##f3, \ + msm_mux_##f4, \ + msm_mux_##f5, \ + msm_mux_##f6, \ + msm_mux_##f7, \ + msm_mux_##f8, \ + msm_mux_##f9, \ + } + +static const msm_pin_function ipq5424_pin_functions[] = { + PINGROUP(0, sdc_data, qspi_data, pwm2, wci_txd, wci_rxd, _, _, _, _), + PINGROUP(1, sdc_data, qspi_data, pwm2, wci_txd, wci_rxd, _, _, _, _), + PINGROUP(2, sdc_data, qspi_data, pwm2, _, _, _, _, _, _), + PINGROUP(3, sdc_data, qspi_data, pwm2, _, _, _, _, _, _), + PINGROUP(4, sdc_cmd, qspi_cs, _, _, _, _, _, _, _), + PINGROUP(5, sdc_clk, qspi_clk, _, _, _, _, _, _, _), + PINGROUP(6, spi0_clk, pwm1, _, cri_trng0, qdss_tracedata_a, _, _, _, _), + PINGROUP(7, spi0_cs, pwm1, _, cri_trng1, qdss_tracedata_a, _, _, _, _), + PINGROUP(8, spi0_miso, pwm1, wci_txd, wci_rxd, _, cri_trng2, qdss_tracedata_a, _, _), + PINGROUP(9, spi0_mosi, pwm1, _, cri_trng3, qdss_tracedata_a, _, _, _, _), + PINGROUP(10, uart0, pwm0, spi11, _, wci_txd, wci_rxd, _, qdss_tracedata_a, _), + PINGROUP(11, uart0, pwm0, spi1, _, wci_txd, wci_rxd, _, qdss_tracedata_a, _), + PINGROUP(12, uart0, pwm0, spi11, _, prng_rosc0, qdss_tracedata_a, _, _, _), + PINGROUP(13, uart0, pwm0, spi11, _, prng_rosc1, qdss_tracedata_a, _, _, _), + PINGROUP(14, i2c0_scl, tsens_max, _, prng_rosc2, qdss_tracedata_a, _, _, _, _), + PINGROUP(15, i2c0_sda, _, prng_rosc3, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(16, core_voltage, i2c1_scl, _, _, _, _, _, _, _), + PINGROUP(17, core_voltage, i2c1_sda, _, _, _, _, _, _, _), + PINGROUP(18, _, _, _, _, _, _, _, _, _), + PINGROUP(19, _, _, _, _, _, _, _, _, _), + PINGROUP(20, mdc_slv, atest_char0, _, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(21, mdio_slv, atest_char1, _, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(22, mdc_mst, atest_char2, _, _, _, _, _, _, _), + PINGROUP(23, mdio_mst, atest_char3, _, _, _, _, _, _, _), + PINGROUP(24, pcie0_clk, PTA10, mac0, _, wsi_clk, _, atest_char, qdss_cti_trig_out_a0, _), + PINGROUP(25, _, _, _, _, _, _, _, _, _), + PINGROUP(26, pcie0_wake, PTA10, mac0, _, wsi_data, _, qdss_cti_trig_in_a0, _, _), + PINGROUP(27, pcie1_clk, i2c11, PTA10, wsi_clk, qdss_cti_trig_out_a1, _, _, _, _), + PINGROUP(28, _, _, _, _, _, _, _, _, _), + PINGROUP(29, pcie1_wake, i2c11, wsi_data, qdss_cti_trig_in_a1, _, _, _, _, _), + PINGROUP(30, pcie2_clk, PTA11, mac1, qdss_cti_trig_out_b0, _, _, _, _, _), + PINGROUP(31, _, _, _, _, _, _, _, _, _), + PINGROUP(32, pcie2_wake, PTA11, mac1, audio_pri0, audio_pri0, qdss_cti_trig_in_b0, _, _, _), + PINGROUP(33, pcie3_clk, PTA11, audio_pri1, audio_pri1, qdss_cti_trig_out_b1, _, _, _, _), + PINGROUP(34, _, _, _, _, _, _, _, _, _), + PINGROUP(35, pcie3_wake, audio_sec1, audio_sec1, qdss_cti_trig_in_b1, _, _, _, _, _), + PINGROUP(36, audio_pri, spi1, audio_sec0, audio_sec0, qdss_tracedata_a, _, _, _, _), + PINGROUP(37, audio_pri, spi1, rx2, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(38, audio_pri, spi1, pll_test, rx1, qdss_tracedata_a, _, _, _, _), + PINGROUP(39, audio_pri, rx0, _, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(40, PTA0_0, wci_txd, wci_rxd, _, atest_tic, _, _, _, _), + PINGROUP(41, PTA0_1, wci_txd, wci_rxd, cxc_data, _, _, _, _, _), + PINGROUP(42, PTA0_2, cxc_clk, _, _, _, _, _, _, _), + PINGROUP(43, uart1, gcc_plltest, _, _, _, _, _, _, _), + PINGROUP(44, uart1, gcc_tlmm, _, _, _, _, _, _, _), + PINGROUP(45, spi10, rx2, audio_sec, gcc_plltest, _, qdss_traceclk_a, _, _, _), + PINGROUP(46, spi1, rx1, audio_sec, dbg_out, qdss_tracectl_a, _, _, _, _), + PINGROUP(47, spi10, rx0, audio_sec, _, _, _, _, _, _), + PINGROUP(48, spi10, audio_sec, _, _, _, _, _, _, _), + PINGROUP(49, resout, _, _, _, _, _, _, _, _), +}; + +static const char *ipq5424_get_function_name(struct udevice *dev, + unsigned int selector) +{ + return ipq5424_functions[selector].name; +} + +static const char *ipq5424_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + return pin_name; +} + +static int ipq5424_get_function_mux(unsigned int pin, unsigned int selector) +{ + unsigned int i; + const msm_pin_function *func = ipq5424_pin_functions + pin; + + for (i = 0; i < 10; i++) + if ((*func)[i] == selector) + return i; + + debug("Can't find requested function for pin:selector %u:%u\n", + pin, selector); + + return -EINVAL; +} + +static const struct msm_pinctrl_data ipq5424_data = { + .pin_data = { + .pin_count = 49, + }, + .functions_count = ARRAY_SIZE(ipq5424_functions), + .get_function_name = ipq5424_get_function_name, + .get_function_mux = ipq5424_get_function_mux, + .get_pin_name = ipq5424_get_pin_name, +}; + +static const struct udevice_id msm_pinctrl_ids[] = { + { .compatible = "qcom,ipq5424-tlmm", .data = (ulong)&ipq5424_data }, + { /* Sentinal */ } +}; + +U_BOOT_DRIVER(pinctrl_ipq5424) = { + .name = "pinctrl_ipq5424", + .id = UCLASS_NOP, + .of_match = msm_pinctrl_ids, + .ops = &msm_pinctrl_ops, + .bind = msm_pinctrl_bind, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/power/pmic/rk8xx.c b/drivers/power/pmic/rk8xx.c index a14555cf472..3bc696d4caa 100644 --- a/drivers/power/pmic/rk8xx.c +++ b/drivers/power/pmic/rk8xx.c @@ -91,7 +91,7 @@ void rk8xx_off_for_plugin(struct udevice *dev) static struct reg_data rk806_init_reg[] = { /* RST_FUN */ - { RK806_REG_SYS_CFG3, GENMASK(7, 6), BIT(7)}, + { RK806_REG_SYS_CFG3, BIT(7), GENMASK(7, 6)}, }; static struct reg_data rk817_init_reg[] = { diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index 7ed435f0202..65b99e89656 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -264,6 +264,15 @@ config REGULATOR_RK8XX by the PMIC device. This driver is controlled by a device tree node which includes voltage limits. +config SPL_REGULATOR_RK8XX + bool "Enable driver for RK8XX regulators in SPL" + depends on SPL_DM_REGULATOR && SPL_PMIC_RK8XX + help + Enable support for the regulator functions of the RK8XX PMIC in SPL. The + driver implements get/set api for the various BUCKS and LDOs supported + by the PMIC device. This driver is controlled by a device tree node + which includes voltage limits. + config DM_REGULATOR_S2MPS11 bool "Enable driver for S2MPS11 regulator" depends on DM_REGULATOR && PMIC_S2MPS11 diff --git a/drivers/power/regulator/act8846.c b/drivers/power/regulator/act8846.c index d3e72da0d35..144032692f6 100644 --- a/drivers/power/regulator/act8846.c +++ b/drivers/power/regulator/act8846.c @@ -29,7 +29,7 @@ enum { REG_SYS0, REG_SYS1, REG1_VOL = 0x10, - REG1_CTL = 0X11, + REG1_CTL = 0x11, REG2_VOL0 = 0x20, REG2_VOL1, REG2_CTL, @@ -41,7 +41,7 @@ enum { REG4_CTL, REG5_VOL = 0x50, REG5_CTL, - REG6_VOL = 0X58, + REG6_VOL = 0x58, REG6_CTL, REG7_VOL = 0x60, REG7_CTL, diff --git a/drivers/power/regulator/qcom_usb_vbus_regulator.c b/drivers/power/regulator/qcom_usb_vbus_regulator.c index 2d58ef5e111..07f118d4797 100644 --- a/drivers/power/regulator/qcom_usb_vbus_regulator.c +++ b/drivers/power/regulator/qcom_usb_vbus_regulator.c @@ -15,14 +15,33 @@ #include <power/pmic.h> #include <power/regulator.h> -#define CMD_OTG 0x50 +enum pm8x50b_vbus { + PM8150B, + PM8550B, +}; + #define OTG_EN BIT(0) -// The 0 bit in this register's bit field is undocumented -#define OTG_CFG 0x56 + #define OTG_EN_SRC_CFG BIT(1) +struct qcom_otg_regs { + u32 otg_cmd; + u32 otg_cfg; +}; struct qcom_usb_vbus_priv { phys_addr_t base; + struct qcom_otg_regs *regs; +}; + +static const struct qcom_otg_regs qcom_otg[] = { + [PM8150B] = { + .otg_cmd = 0x40, + .otg_cfg = 0x53, + }, + [PM8550B] = { + .otg_cmd = 0x50, + .otg_cfg = 0x56, + }, }; static int qcom_usb_vbus_regulator_of_to_plat(struct udevice *dev) @@ -38,8 +57,9 @@ static int qcom_usb_vbus_regulator_of_to_plat(struct udevice *dev) static int qcom_usb_vbus_regulator_get_enable(struct udevice *dev) { + const struct qcom_otg_regs *regs = &qcom_otg[dev_get_driver_data(dev)]; struct qcom_usb_vbus_priv *priv = dev_get_priv(dev); - int otg_en_reg = priv->base + CMD_OTG; + int otg_en_reg = priv->base + regs->otg_cmd; int ret; ret = pmic_reg_read(dev->parent, otg_en_reg); @@ -53,8 +73,9 @@ static int qcom_usb_vbus_regulator_get_enable(struct udevice *dev) static int qcom_usb_vbus_regulator_set_enable(struct udevice *dev, bool enable) { + const struct qcom_otg_regs *regs = &qcom_otg[dev_get_driver_data(dev)]; struct qcom_usb_vbus_priv *priv = dev_get_priv(dev); - int otg_en_reg = priv->base + CMD_OTG; + int otg_en_reg = priv->base + regs->otg_cmd; int ret; if (enable) { @@ -76,8 +97,9 @@ static int qcom_usb_vbus_regulator_set_enable(struct udevice *dev, bool enable) static int qcom_usb_vbus_regulator_probe(struct udevice *dev) { + const struct qcom_otg_regs *regs = &qcom_otg[dev_get_driver_data(dev)]; struct qcom_usb_vbus_priv *priv = dev_get_priv(dev); - int otg_cfg_reg = priv->base + OTG_CFG; + int otg_cfg_reg = priv->base + regs->otg_cfg; int ret; /* Disable HW logic for VBUS enable */ @@ -96,7 +118,8 @@ static const struct dm_regulator_ops qcom_usb_vbus_regulator_ops = { }; static const struct udevice_id qcom_usb_vbus_regulator_ids[] = { - { .compatible = "qcom,pm8150b-vbus-reg"}, + { .compatible = "qcom,pm8150b-vbus-reg", .data = PM8150B }, + { .compatible = "qcom,pm8550b-vbus-reg", .data = PM8550B }, { }, }; diff --git a/drivers/power/regulator/rk8xx.c b/drivers/power/regulator/rk8xx.c index 368675ebb9f..88453bb7bdb 100644 --- a/drivers/power/regulator/rk8xx.c +++ b/drivers/power/regulator/rk8xx.c @@ -16,10 +16,6 @@ #include <power/pmic.h> #include <power/regulator.h> -#ifndef CONFIG_XPL_BUILD -#define ENABLE_DRIVER -#endif - /* Not used or exisit register and configure */ #define NA 0xff @@ -202,7 +198,7 @@ static const struct rk8xx_reg_info rk818_buck[] = { { 1800000, 100000, REG_BUCK4_ON_VSEL, REG_BUCK4_SLP_VSEL, REG_BUCK4_CONFIG, RK818_BUCK4_VSEL_MASK, 0x00, 0x1f }, }; -#ifdef ENABLE_DRIVER +#if CONFIG_IS_ENABLED(REGULATOR_RK8XX) static const struct rk8xx_reg_info rk806_nldo[] = { /* nldo 1 */ { 500000, 12500, RK806_NLDO_ON_VSEL(1), RK806_NLDO_SLP_VSEL(1), NA, RK806_NLDO_VSEL_MASK, 0x00, 0xe7}, @@ -454,7 +450,7 @@ static int _buck_set_enable(struct udevice *pmic, int buck, bool enable) return ret; } -#ifdef ENABLE_DRIVER +#if CONFIG_IS_ENABLED(REGULATOR_RK8XX) static int _buck_set_suspend_value(struct udevice *pmic, int buck, int uvolt) { const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck, uvolt); diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index de312656746..e4c676d75c2 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -126,3 +126,9 @@ config PWM_TI_EHRPWM default y help PWM driver support for the EHRPWM controller found on TI SOCs. + +config PWM_TI_ECAP + bool "Enable support for ECAP PWM" + depends on DM_PWM && ARCH_OMAP2PLUS + help + PWM driver support for the ECAP controller found on TI SOCs. diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 76305b93bc9..2682c536c6f 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_PWM_TEGRA) += tegra_pwm.o obj-$(CONFIG_PWM_STM32) += pwm-stm32.o obj-$(CONFIG_PWM_SUNXI) += sunxi_pwm.o obj-$(CONFIG_PWM_TI_EHRPWM) += pwm-ti-ehrpwm.o +obj-$(CONFIG_PWM_TI_ECAP) += pwm-tiecap.o diff --git a/drivers/pwm/pwm-ti-ehrpwm.c b/drivers/pwm/pwm-ti-ehrpwm.c index 563109ef0f8..135ea3b4321 100644 --- a/drivers/pwm/pwm-ti-ehrpwm.c +++ b/drivers/pwm/pwm-ti-ehrpwm.c @@ -399,7 +399,7 @@ static int ti_ehrpwm_of_to_plat(struct udevice *dev) return -EINVAL; } - dev_dbg(dev, "regs=0x%08lx\n", priv->regs); + dev_dbg(dev, "regs=0x%08x\n", priv->regs); return 0; } diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c new file mode 100644 index 00000000000..cfd6c871b57 --- /dev/null +++ b/drivers/pwm/pwm-tiecap.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * ECAP PWM driver + * + * Copyright (C) 2025 BayLibre, SAS + * Author: Sukrut Bellary <sbellary@baylibre.com> + */ + +#include <clk.h> +#include <div64.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <pwm.h> +#include <asm/io.h> + +/* eCAP module registers */ +#define ECAP_PWM_CAP1 0x08 +#define ECAP_PWM_CAP2 0x0C +#define ECAP_PWM_CAP3 0x10 +#define ECAP_PWM_CAP4 0x14 + +#define ECAP_PWM_ECCTL2 0x2A +#define ECAP_PWM_ECCTL2_APWM_POL_LOW BIT(10) +#define ECAP_PWM_ECCTL2_APWM_MODE BIT(9) +#define ECAP_PWM_ECCTL2_TSCTR_FREERUN BIT(4) +#define ECAP_PWM_ECCTL2_SYNC_SEL_DISA (BIT(7) | BIT(6)) + +#define NSEC_PER_SEC 1000000000L + +enum tiecap_pwm_polarity { + TIECAP_PWM_POLARITY_NORMAL, + TIECAP_PWM_POLARITY_INVERSED +}; + +enum tiecap_pwm_state { + TIECAP_APWM_DISABLED, + TIECAP_APWM_ENABLED +}; + +struct tiecap_pwm_priv { + fdt_addr_t regs; + u32 clk_rate; + enum tiecap_pwm_state pwm_state; +}; + +static int tiecap_pwm_set_config(struct udevice *dev, uint channel, + uint period_ns, uint duty_ns) +{ + struct tiecap_pwm_priv *priv = dev_get_priv(dev); + u32 period_cycles, duty_cycles; + unsigned long long c; + u16 value; + + c = priv->clk_rate; + c = c * period_ns; + do_div(c, NSEC_PER_SEC); + period_cycles = (u32)c; + + if (period_cycles < 1) { + period_cycles = 1; + duty_cycles = 1; + } else { + c = priv->clk_rate; + c = c * duty_ns; + do_div(c, NSEC_PER_SEC); + duty_cycles = (u32)c; + } + + value = readw(priv->regs + ECAP_PWM_ECCTL2); + + /* Configure APWM mode & disable sync option */ + value |= ECAP_PWM_ECCTL2_APWM_MODE | ECAP_PWM_ECCTL2_SYNC_SEL_DISA; + + writew(value, priv->regs + ECAP_PWM_ECCTL2); + + if (priv->pwm_state == TIECAP_APWM_DISABLED) { + /* Update active registers */ + writel(duty_cycles, priv->regs + ECAP_PWM_CAP2); + writel(period_cycles, priv->regs + ECAP_PWM_CAP1); + } else { + /* Update shadow registers to configure period and + * compare values. This helps current pwm period to + * complete on reconfiguring. + */ + writel(duty_cycles, priv->regs + ECAP_PWM_CAP4); + writel(period_cycles, priv->regs + ECAP_PWM_CAP3); + } + + return 0; +} + +static int tiecap_pwm_set_enable(struct udevice *dev, uint channel, bool enable) +{ + struct tiecap_pwm_priv *priv = dev_get_priv(dev); + u16 value; + + value = readw(priv->regs + ECAP_PWM_ECCTL2); + + if (enable) { + /* + * Enable 'Free run Time stamp counter mode' to start counter + * and 'APWM mode' to enable APWM output + */ + value |= ECAP_PWM_ECCTL2_TSCTR_FREERUN | ECAP_PWM_ECCTL2_APWM_MODE; + priv->pwm_state = TIECAP_APWM_ENABLED; + } else { + /* Disable 'Free run Time stamp counter mode' to stop counter + * and 'APWM mode' to put APWM output to low + */ + value &= ~(ECAP_PWM_ECCTL2_TSCTR_FREERUN | ECAP_PWM_ECCTL2_APWM_MODE); + priv->pwm_state = TIECAP_APWM_DISABLED; + } + + writew(value, priv->regs + ECAP_PWM_ECCTL2); + + return 0; +} + +static int tiecap_pwm_set_invert(struct udevice *dev, uint channel, + bool polarity) +{ + struct tiecap_pwm_priv *priv = dev_get_priv(dev); + u16 value; + + value = readw(priv->regs + ECAP_PWM_ECCTL2); + + if (polarity == TIECAP_PWM_POLARITY_INVERSED) + /* Duty cycle defines LOW period of PWM */ + value |= ECAP_PWM_ECCTL2_APWM_POL_LOW; + else + /* Duty cycle defines HIGH period of PWM */ + value &= ~ECAP_PWM_ECCTL2_APWM_POL_LOW; + + writew(value, priv->regs + ECAP_PWM_ECCTL2); + + return 0; +} + +static int tiecap_pwm_of_to_plat(struct udevice *dev) +{ + struct tiecap_pwm_priv *priv = dev_get_priv(dev); + + priv->regs = dev_read_addr(dev); + if (priv->regs == FDT_ADDR_T_NONE) { + dev_err(dev, "invalid address\n"); + return -EINVAL; + } + + dev_dbg(dev, "regs=0x%08x\n", priv->regs); + + return 0; +} + +static int tiecap_pwm_probe(struct udevice *dev) +{ + struct tiecap_pwm_priv *priv = dev_get_priv(dev); + struct clk clk; + int err; + + err = clk_get_by_name(dev, "fck", &clk); + if (err) { + dev_err(dev, "failed to get clock\n"); + return err; + } + + priv->clk_rate = clk_get_rate(&clk); + if (IS_ERR_VALUE(priv->clk_rate) || !priv->clk_rate) { + dev_err(dev, "failed to get clock rate\n"); + if (IS_ERR_VALUE(priv->clk_rate)) + return priv->clk_rate; + + return -EINVAL; + } + + return 0; +} + +static const struct pwm_ops tiecap_pwm_ops = { + .set_config = tiecap_pwm_set_config, + .set_enable = tiecap_pwm_set_enable, + .set_invert = tiecap_pwm_set_invert, +}; + +static const struct udevice_id tiecap_pwm_ids[] = { + { .compatible = "ti,am3352-ecap" }, + { .compatible = "ti,am33xx-ecap" }, + { } +}; + +U_BOOT_DRIVER(tiecap_pwm) = { + .name = "tiecap_pwm", + .id = UCLASS_PWM, + .of_match = tiecap_pwm_ids, + .ops = &tiecap_pwm_ops, + .probe = tiecap_pwm_probe, + .of_to_plat = tiecap_pwm_of_to_plat, + .priv_auto = sizeof(struct tiecap_pwm_priv), +}; diff --git a/drivers/qe/qe.c b/drivers/qe/qe.c index 9631337b8d9..69b7de084e5 100644 --- a/drivers/qe/qe.c +++ b/drivers/qe/qe.c @@ -243,7 +243,7 @@ void u_qe_init(void) CFG_SYS_FSL_QSPI_BASE); if (src == BOOT_SOURCE_SD_MMC) { - int dev = CONFIG_SYS_MMC_ENV_DEV; + int dev = CONFIG_ENV_MMC_DEVICE_INDEX; u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512; u32 blk = CONFIG_SYS_QE_FW_ADDR / 512; @@ -252,7 +252,7 @@ void u_qe_init(void) return; } addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH); - struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV); + struct mmc *mmc = find_mmc_device(CONFIG_ENV_MMC_DEVICE_INDEX); if (!mmc) { free(addr); @@ -277,7 +277,7 @@ void u_qe_init(void) void *addr = (void *)CONFIG_SYS_QE_FW_ADDR; #ifdef CONFIG_SYS_QE_FMAN_FW_IN_MMC - int dev = CONFIG_SYS_MMC_ENV_DEV; + int dev = CONFIG_ENV_MMC_DEVICE_INDEX; u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512; u32 blk = CONFIG_SYS_QE_FW_ADDR / 512; @@ -286,7 +286,7 @@ void u_qe_init(void) return; } addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH); - struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV); + struct mmc *mmc = find_mmc_device(CONFIG_ENV_MMC_DEVICE_INDEX); if (!mmc) { printf("\nMMC cannot find device for ucode\n"); diff --git a/drivers/ram/Kconfig b/drivers/ram/Kconfig index 39d03e8d3d3..edb8e254d5b 100644 --- a/drivers/ram/Kconfig +++ b/drivers/ram/Kconfig @@ -1,3 +1,5 @@ +menu "RAM drivers using Driver Model" + config RAM bool "Enable RAM drivers using Driver Model" depends on DM @@ -136,3 +138,5 @@ source "drivers/ram/stm32mp1/Kconfig" source "drivers/ram/starfive/Kconfig" source "drivers/ram/sunxi/Kconfig" source "drivers/ram/thead/Kconfig" + +endmenu diff --git a/drivers/ram/k3-ddrss/k3-ddrss.c b/drivers/ram/k3-ddrss/k3-ddrss.c index ff87faf6a22..6590d57ad84 100644 --- a/drivers/ram/k3-ddrss/k3-ddrss.c +++ b/drivers/ram/k3-ddrss/k3-ddrss.c @@ -35,7 +35,7 @@ #define DDRSS_V2A_CTL_REG_SDRAM_IDX_CALC(x) ((ilog2(x) - 16) << 5) #define DDRSS_V2A_CTL_REG_SDRAM_IDX_MASK (~(0x1F << 0x5)) -#define DDRSS_V2A_CTL_REG_REGION_IDX_MASK (~(0X1F)) +#define DDRSS_V2A_CTL_REG_REGION_IDX_MASK (~(0x1F)) #define DDRSS_V2A_CTL_REG_REGION_IDX_DEFAULT 0xF #define DDRSS_ECC_CTRL_REG_DEFAULT 0x0 diff --git a/drivers/ram/octeon/octeon3_lmc.c b/drivers/ram/octeon/octeon3_lmc.c index eaef0fa5c12..dc4b8f8cf23 100644 --- a/drivers/ram/octeon/octeon3_lmc.c +++ b/drivers/ram/octeon/octeon3_lmc.c @@ -8692,7 +8692,7 @@ int init_octeon3_ddr3_interface(struct ddr_priv *priv, bank_bits = min((int)bank_bits, 4); spd_package = - 0XFF & read_spd(&dimm_config_table[0], 0, + 0xFF & read_spd(&dimm_config_table[0], 0, DDR4_SPD_PACKAGE_TYPE); if (spd_package & 0x80) { // non-monolithic device is_stacked_die = ((spd_package & 0x73) == 0x11); diff --git a/drivers/ram/rockchip/Kconfig b/drivers/ram/rockchip/Kconfig index 67c63ecba04..d707d09c1c8 100644 --- a/drivers/ram/rockchip/Kconfig +++ b/drivers/ram/rockchip/Kconfig @@ -15,6 +15,7 @@ if RAM_ROCKCHIP config RAM_ROCKCHIP_DEBUG bool "Rockchip ram drivers debugging" + depends on DEBUG_UART default y help This enables debugging ram driver API's for the platforms diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c index 0e37ea93fbc..b275407d4ac 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr.c +++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c @@ -12,6 +12,7 @@ #include <timer.h> #include <asm/io.h> #include <asm/arch/ddr.h> +#include <dm/device.h> #include <linux/bitops.h> #include <linux/delay.h> #include <linux/iopoll.h> @@ -19,7 +20,8 @@ #include "stm32mp1_ddr.h" #include "stm32mp1_ddr_regs.h" -#define RCC_DDRITFCR 0xD8 +#define RCC_DDRITFCR_STM32MP13xx 0x5c0 +#define RCC_DDRITFCR_STM32MP15xx 0xd8 #define RCC_DDRITFCR_DDRCAPBRST (BIT(14)) #define RCC_DDRITFCR_DDRCAXIRST (BIT(15)) @@ -66,9 +68,19 @@ struct reg_desc { #define DDRCTL_REG_REG_SIZE 25 /* st,ctl-reg */ #define DDRCTL_REG_TIMING_SIZE 12 /* st,ctl-timing */ #define DDRCTL_REG_MAP_SIZE 9 /* st,ctl-map */ -#define DDRCTL_REG_PERF_SIZE 17 /* st,ctl-perf */ -#define DDRPHY_REG_REG_SIZE 11 /* st,phy-reg */ +#define DDRCTL_REG_PERF_SIZE_STM32MP13xx 11 /* st,ctl-perf */ +#define DDRCTL_REG_PERF_SIZE_STM32MP15xx 17 /* st,ctl-perf */ +#define DDRCTL_REG_PERF_SIZE \ + (IS_ENABLED(CONFIG_STM32MP15X) ? DDRCTL_REG_PERF_SIZE_STM32MP15xx : \ + DDRCTL_REG_PERF_SIZE_STM32MP13xx) + +#define DDRPHY_REG_REG_SIZE_STM32MP13xx 9 /* st,phy-reg */ +#define DDRPHY_REG_REG_SIZE_STM32MP15xx 11 /* st,phy-reg */ +#define DDRPHY_REG_REG_SIZE \ + (IS_ENABLED(CONFIG_STM32MP15X) ? DDRPHY_REG_REG_SIZE_STM32MP15xx : \ + DDRPHY_REG_REG_SIZE_STM32MP13xx) + #define DDRPHY_REG_TIMING_SIZE 10 /* st,phy-timing */ #define DDRCTL_REG_REG(x) DDRCTL_REG(x, stm32mp1_ddrctrl_reg) @@ -142,12 +154,14 @@ static const struct reg_desc ddr_perf[DDRCTL_REG_PERF_SIZE] = { DDRCTL_REG_PERF(pcfgqos1_0), DDRCTL_REG_PERF(pcfgwqos0_0), DDRCTL_REG_PERF(pcfgwqos1_0), +#if IS_ENABLED(CONFIG_STM32MP15X) DDRCTL_REG_PERF(pcfgr_1), DDRCTL_REG_PERF(pcfgw_1), DDRCTL_REG_PERF(pcfgqos0_1), DDRCTL_REG_PERF(pcfgqos1_1), DDRCTL_REG_PERF(pcfgwqos0_1), DDRCTL_REG_PERF(pcfgwqos1_1), +#endif }; #define DDRPHY_REG_REG(x) DDRPHY_REG(x, stm32mp1_ddrphy_reg) @@ -161,8 +175,10 @@ static const struct reg_desc ddrphy_reg[DDRPHY_REG_REG_SIZE] = { DDRPHY_REG_REG(zq0cr1), DDRPHY_REG_REG(dx0gcr), DDRPHY_REG_REG(dx1gcr), +#if IS_ENABLED(CONFIG_STM32MP15X) DDRPHY_REG_REG(dx2gcr), DDRPHY_REG_REG(dx3gcr), +#endif }; #define DDRPHY_REG_TIMING(x) DDRPHY_REG(x, stm32mp1_ddrphy_timing) @@ -211,6 +227,7 @@ static const struct reg_desc ddrphy_dyn[] = { DDRPHY_REG_DYN(dx1dllcr), DDRPHY_REG_DYN(dx1dqtr), DDRPHY_REG_DYN(dx1dqstr), +#if IS_ENABLED(CONFIG_STM32MP15X) DDRPHY_REG_DYN(dx2gsr0), DDRPHY_REG_DYN(dx2gsr1), DDRPHY_REG_DYN(dx2dllcr), @@ -221,6 +238,7 @@ static const struct reg_desc ddrphy_dyn[] = { DDRPHY_REG_DYN(dx3dllcr), DDRPHY_REG_DYN(dx3dqtr), DDRPHY_REG_DYN(dx3dqstr), +#endif }; #define DDRPHY_REG_DYN_SIZE ARRAY_SIZE(ddrphy_dyn) @@ -287,6 +305,24 @@ const char *base_name[] = { [DDRPHY_BASE] = "phy", }; +bool is_stm32mp13_ddrc(const struct ddr_info *priv) +{ + if (IS_ENABLED(CONFIG_STM32MP13X) && !IS_ENABLED(CONFIG_STM32MP15X)) + return true; /* STM32MP13xx only build */ + else if (!IS_ENABLED(CONFIG_STM32MP13X) && IS_ENABLED(CONFIG_STM32MP15X)) + return false; /* STM32MP15xx only build */ + + /* Combined STM32MP13xx and STM32MP15xx build */ + return device_is_compatible(priv->dev, "st,stm32mp13-ddr"); +} + +static u32 get_rcc_ddritfcr(const struct ddr_info *priv) +{ + return priv->rcc + (is_stm32mp13_ddrc(priv) ? + RCC_DDRITFCR_STM32MP13xx : + RCC_DDRITFCR_STM32MP15xx); +} + static u32 get_base_addr(const struct ddr_info *priv, enum base_type base) { if (base == DDRPHY_BASE) @@ -295,6 +331,21 @@ static u32 get_base_addr(const struct ddr_info *priv, enum base_type base) return (u32)priv->ctl; } +static u32 get_type_size(const struct ddr_info *priv, enum reg_type type) +{ + bool is_mp13 = is_stm32mp13_ddrc(priv); + + if (type == REG_PERF) + return is_mp13 ? DDRCTL_REG_PERF_SIZE_STM32MP13xx : + DDRCTL_REG_PERF_SIZE_STM32MP15xx; + else if (type == REGPHY_REG) + return is_mp13 ? DDRPHY_REG_REG_SIZE_STM32MP13xx : + DDRPHY_REG_REG_SIZE_STM32MP15xx; + + /* Everything else is the default size */ + return ddr_registers[type].size; +} + static void set_reg(const struct ddr_info *priv, enum reg_type type, const void *param) @@ -304,9 +355,10 @@ static void set_reg(const struct ddr_info *priv, enum base_type base = ddr_registers[type].base; u32 base_addr = get_base_addr(priv, base); const struct reg_desc *desc = ddr_registers[type].desc; + u32 size = get_type_size(priv, type); log_debug("init %s\n", ddr_registers[type].name); - for (i = 0; i < ddr_registers[type].size; i++) { + for (i = 0; i < size; i++) { ptr = (unsigned int *)(base_addr + desc[i].offset); if (desc[i].par_offset == INVALID_OFFSET) { log_err("invalid parameter offset for %s", desc[i].name); @@ -656,12 +708,13 @@ static void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl, static void stm32mp1_asr_enable(struct ddr_info *priv, const u32 pwrctl) { struct stm32mp1_ddrctl *ctl = priv->ctl; + u32 rcc_ddritfcr = get_rcc_ddritfcr(priv); /* SSR is the best we can do. */ if (!(pwrctl & DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE)) return; - clrsetbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCKMOD_MASK, + clrsetbits_le32(rcc_ddritfcr, RCC_DDRITFCR_DDRCKMOD_MASK, RCC_DDRITFCR_DDRCKMOD_ASR); start_sw_done(ctl); @@ -691,6 +744,7 @@ __maybe_unused void stm32mp1_ddr_init(struct ddr_info *priv, const struct stm32mp1_ddr_config *config) { + u32 rcc_ddritfcr = get_rcc_ddritfcr(priv); u32 pir; int ret = -EINVAL; char bus_width; @@ -732,12 +786,12 @@ start: * 1.1 RESETS: presetn, core_ddrc_rstn, aresetn */ /* Assert All DDR part */ - setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAPBRST); - setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAXIRST); - setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCORERST); - setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYAPBRST); - setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYRST); - setbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYCTLRST); + setbits_le32(rcc_ddritfcr, RCC_DDRITFCR_DDRCAPBRST); + setbits_le32(rcc_ddritfcr, RCC_DDRITFCR_DDRCAXIRST); + setbits_le32(rcc_ddritfcr, RCC_DDRITFCR_DDRCORERST); + setbits_le32(rcc_ddritfcr, RCC_DDRITFCR_DPHYAPBRST); + setbits_le32(rcc_ddritfcr, RCC_DDRITFCR_DPHYRST); + setbits_le32(rcc_ddritfcr, RCC_DDRITFCR_DPHYCTLRST); /* 1.2. start CLOCK */ if (stm32mp1_ddr_clk_enable(priv, config->info.speed)) @@ -746,12 +800,12 @@ start: /* 1.3. deassert reset */ /* de-assert PHY rstn and ctl_rstn via DPHYRST and DPHYCTLRST */ - clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYRST); - clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYCTLRST); + clrbits_le32(rcc_ddritfcr, RCC_DDRITFCR_DPHYRST); + clrbits_le32(rcc_ddritfcr, RCC_DDRITFCR_DPHYCTLRST); /* De-assert presetn once the clocks are active * and stable via DDRCAPBRST bit */ - clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAPBRST); + clrbits_le32(rcc_ddritfcr, RCC_DDRITFCR_DDRCAPBRST); /* 1.4. wait 128 cycles to permit initialization of end logic */ udelay(2); @@ -781,9 +835,9 @@ start: goto start; /* 2. deassert reset signal core_ddrc_rstn, aresetn and presetn */ - clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCORERST); - clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAXIRST); - clrbits_le32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYAPBRST); + clrbits_le32(rcc_ddritfcr, RCC_DDRITFCR_DDRCORERST); + clrbits_le32(rcc_ddritfcr, RCC_DDRITFCR_DDRCAXIRST); + clrbits_le32(rcc_ddritfcr, RCC_DDRITFCR_DPHYAPBRST); /* 3. start PHY init by accessing relevant PUBL registers * (DXGCR, DCR, PTR*, MR*, DTPR*) @@ -854,9 +908,12 @@ start: /* Enable auto-self-refresh, which saves a bit of power at runtime. */ stm32mp1_asr_enable(priv, config->c_reg.pwrctl); - /* enable uMCTL2 AXI port 0 and 1 */ + /* enable uMCTL2 AXI port 0 */ setbits_le32(&priv->ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN); - setbits_le32(&priv->ctl->pctrl_1, DDRCTRL_PCTRL_N_PORT_EN); + + /* enable uMCTL2 AXI port 1 only on STM32MP15xx with 32bit DRAM bus */ + if (!is_stm32mp13_ddrc(priv)) + setbits_le32(&priv->ctl->pctrl_1, DDRCTRL_PCTRL_N_PORT_EN); if (INTERACTIVE(STEP_DDR_READY)) goto start; diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.h b/drivers/ram/stm32mp1/stm32mp1_ddr.h index 861efff92be..3621e6c9a1b 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ddr.h +++ b/drivers/ram/stm32mp1/stm32mp1_ddr.h @@ -105,12 +105,14 @@ struct stm32mp1_ddrctrl_perf { u32 pcfgqos1_0; u32 pcfgwqos0_0; u32 pcfgwqos1_0; +#if IS_ENABLED(CONFIG_STM32MP15X) u32 pcfgr_1; u32 pcfgw_1; u32 pcfgqos0_1; u32 pcfgqos1_1; u32 pcfgwqos0_1; u32 pcfgwqos1_1; +#endif }; struct stm32mp1_ddrphy_reg { @@ -123,8 +125,10 @@ struct stm32mp1_ddrphy_reg { u32 zq0cr1; u32 dx0gcr; u32 dx1gcr; +#if IS_ENABLED(CONFIG_STM32MP15X) u32 dx2gcr; u32 dx3gcr; +#endif }; struct stm32mp1_ddrphy_timing { @@ -181,4 +185,6 @@ bool stm32mp1_ddr_interactive( enum stm32mp1_ddr_interact_step step, const struct stm32mp1_ddr_config *config); +bool is_stm32mp13_ddrc(const struct ddr_info *priv); + #endif diff --git a/drivers/ram/stm32mp1/stm32mp1_ram.c b/drivers/ram/stm32mp1/stm32mp1_ram.c index e9cd6229ec4..5f9b91d50e4 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ram.c +++ b/drivers/ram/stm32mp1/stm32mp1_ram.c @@ -33,6 +33,7 @@ static const char *const clkname[] = { int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed) { + bool is_mp13 = is_stm32mp13_ddrc(priv); unsigned long ddrphy_clk; unsigned long ddr_clk; struct clk clk; @@ -40,6 +41,10 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed) unsigned int idx; for (idx = 0; idx < ARRAY_SIZE(clkname); idx++) { + /* DDRC2 clock are available only on STM32MP15xx */ + if (is_mp13 && !strcmp(clkname[idx], "ddrc2")) + continue; + ret = clk_get_by_name(priv->dev, clkname[idx], &clk); if (!ret) diff --git a/drivers/remoteproc/ti_k3_r5f_rproc.c b/drivers/remoteproc/ti_k3_r5f_rproc.c index 57268e7f8ff..f4bab6868ee 100644 --- a/drivers/remoteproc/ti_k3_r5f_rproc.c +++ b/drivers/remoteproc/ti_k3_r5f_rproc.c @@ -834,8 +834,14 @@ static int k3_r5f_probe(struct udevice *dev) return 0; } + ret = k3_r5f_proc_request(core); + if (ret) + return ret; + /* Make sure Local reset is asserted. Redundant? */ reset_assert(&core->reset); + + ti_sci_proc_release(&core->tsp); } ret = k3_r5f_rproc_configure(core); diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index a0d079c4555..e92bb8a7c39 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -28,13 +28,6 @@ config STI_RESET Say Y if you want to control reset signals provided by system config block. -config STM32_RESET - bool "Enable the STM32 reset" - depends on ARCH_STM32 || ARCH_STM32MP - help - Support for reset controllers on STMicroelectronics STM32 family SoCs. - This reset driver is compatible with STM32 F4/F7 and H7 SoCs. - config TEGRA_CAR_RESET bool "Enable Tegra CAR-based reset driver" depends on TEGRA_CAR @@ -258,4 +251,6 @@ config RESET_SPACEMIT_K1 help Support for SPACEMIT's K1 Reset system. Basic Assert/Deassert is supported. + +source "drivers/reset/stm32/Kconfig" endmenu diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 1dd3cd99a14..ee5b009d134 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_DM_RESET) += reset-uclass.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-reset.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-reset-test.o obj-$(CONFIG_STI_RESET) += sti-reset.o -obj-$(CONFIG_STM32_RESET) += stm32-reset.o obj-$(CONFIG_TEGRA_CAR_RESET) += tegra-car-reset.o obj-$(CONFIG_TEGRA186_RESET) += tegra186-reset.o obj-$(CONFIG_RESET_AIROHA) += reset-airoha.o @@ -36,3 +35,6 @@ obj-$(CONFIG_RESET_AT91) += reset-at91.o obj-$(CONFIG_$(PHASE_)RESET_JH7110) += reset-jh7110.o obj-$(CONFIG_RESET_RZG2L_USBPHY_CTRL) += reset-rzg2l-usbphy-ctrl.o obj-$(CONFIG_RESET_SPACEMIT_K1) += reset-spacemit-k1.o + +obj-$(CONFIG_ARCH_STM32) += stm32/ +obj-$(CONFIG_ARCH_STM32MP) += stm32/ diff --git a/drivers/reset/stm32-reset.c b/drivers/reset/stm32-reset.c deleted file mode 100644 index 9d4f361b251..00000000000 --- a/drivers/reset/stm32-reset.c +++ /dev/null @@ -1,97 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2017, STMicroelectronics - All Rights Reserved - * Author(s): Patrice Chotard, <patrice.chotard@foss.st.com> for STMicroelectronics. - */ - -#define LOG_CATEGORY UCLASS_RESET - -#include <dm.h> -#include <errno.h> -#include <log.h> -#include <malloc.h> -#include <reset-uclass.h> -#include <stm32_rcc.h> -#include <asm/io.h> -#include <dm/device_compat.h> -#include <linux/bitops.h> - -/* offset of register without set/clear management */ -#define RCC_MP_GCR_OFFSET 0x10C - -/* reset clear offset for STM32MP RCC */ -#define RCC_CL 0x4 - -struct stm32_reset_priv { - fdt_addr_t base; -}; - -static int stm32_reset_assert(struct reset_ctl *reset_ctl) -{ - struct stm32_reset_priv *priv = dev_get_priv(reset_ctl->dev); - int bank = (reset_ctl->id / (sizeof(u32) * BITS_PER_BYTE)) * 4; - int offset = reset_ctl->id % (sizeof(u32) * BITS_PER_BYTE); - - dev_dbg(reset_ctl->dev, "reset id = %ld bank = %d offset = %d)\n", - reset_ctl->id, bank, offset); - - if (dev_get_driver_data(reset_ctl->dev) == STM32MP1) - if (bank != RCC_MP_GCR_OFFSET) - /* reset assert is done in rcc set register */ - writel(BIT(offset), priv->base + bank); - else - clrbits_le32(priv->base + bank, BIT(offset)); - else - setbits_le32(priv->base + bank, BIT(offset)); - - return 0; -} - -static int stm32_reset_deassert(struct reset_ctl *reset_ctl) -{ - struct stm32_reset_priv *priv = dev_get_priv(reset_ctl->dev); - int bank = (reset_ctl->id / (sizeof(u32) * BITS_PER_BYTE)) * 4; - int offset = reset_ctl->id % (sizeof(u32) * BITS_PER_BYTE); - - dev_dbg(reset_ctl->dev, "reset id = %ld bank = %d offset = %d)\n", - reset_ctl->id, bank, offset); - - if (dev_get_driver_data(reset_ctl->dev) == STM32MP1) - if (bank != RCC_MP_GCR_OFFSET) - /* reset deassert is done in rcc clr register */ - writel(BIT(offset), priv->base + bank + RCC_CL); - else - setbits_le32(priv->base + bank, BIT(offset)); - else - clrbits_le32(priv->base + bank, BIT(offset)); - - return 0; -} - -static const struct reset_ops stm32_reset_ops = { - .rst_assert = stm32_reset_assert, - .rst_deassert = stm32_reset_deassert, -}; - -static int stm32_reset_probe(struct udevice *dev) -{ - struct stm32_reset_priv *priv = dev_get_priv(dev); - - priv->base = dev_read_addr(dev); - if (priv->base == FDT_ADDR_T_NONE) { - /* for MFD, get address of parent */ - priv->base = dev_read_addr(dev->parent); - if (priv->base == FDT_ADDR_T_NONE) - return -EINVAL; - } - - return 0; -} - -U_BOOT_DRIVER(stm32_rcc_reset) = { - .name = "stm32_rcc_reset", - .id = UCLASS_RESET, - .probe = stm32_reset_probe, - .priv_auto = sizeof(struct stm32_reset_priv), - .ops = &stm32_reset_ops, -}; diff --git a/drivers/reset/stm32/Kconfig b/drivers/reset/stm32/Kconfig new file mode 100644 index 00000000000..39dcfa0a9ca --- /dev/null +++ b/drivers/reset/stm32/Kconfig @@ -0,0 +1,23 @@ +config RESET_STM32 + bool "Enable the STM32 reset" + depends on ARCH_STM32 + default y + help + Support for reset controllers on STMicroelectronics STM32 family SoCs. + This reset driver is compatible with STM32 F4/F7 and H7 SoCs. + +config RESET_STM32MP1 + bool "Enable the STM32MP1 reset" + depends on STM32MP13X || STM32MP15X + default y + help + Support for reset controllers on STMicroelectronics STM32MP1 family SoCs. + This reset driver is compatible with STM32MP13 and STM32MP15 SoCs. + +config RESET_STM32MP25 + bool "Enable the STM32MP25 reset" + depends on STM32MP25X + default y + help + Support for reset controllers on STMicroelectronics STM32MP2 family SoCs. + This reset driver is compatible with STM32MP25 SoCs. diff --git a/drivers/reset/stm32/Makefile b/drivers/reset/stm32/Makefile new file mode 100644 index 00000000000..c31ae524ba1 --- /dev/null +++ b/drivers/reset/stm32/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (C) 2024, STMicroelectronics - All Rights Reserved + +obj-y += stm32-reset-core.o + +obj-$(CONFIG_RESET_STM32) += stm32-reset.o +obj-$(CONFIG_RESET_STM32MP1) += stm32-reset-mp1.o +obj-$(CONFIG_RESET_STM32MP25) += stm32-reset-mp25.o diff --git a/drivers/reset/stm32/stm32-reset-core.c b/drivers/reset/stm32/stm32-reset-core.c new file mode 100644 index 00000000000..7dd92e07e1a --- /dev/null +++ b/drivers/reset/stm32/stm32-reset-core.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause +/* + * Copyright (C) 2024, STMicroelectronics - All Rights Reserved + * Author(s): Gabriel Fernandez, <gabriel.fernandez@foss.st.com> for STMicroelectronics. + */ + +#include <dm.h> +#include <reset-uclass.h> +#include <stm32-reset-core.h> +#include <stm32_rcc.h> +#include <dm/device_compat.h> +#include <linux/iopoll.h> + +static int stm32_reset_update(struct reset_ctl *reset_ctl, bool status) +{ + struct stm32_reset_priv *priv = dev_get_priv(reset_ctl->dev); + const struct stm32_reset_data *data = priv->data; + const struct stm32_reset_cfg *ptr_line; + fdt_addr_t addr; + + assert(priv->data->get_reset_line); + + ptr_line = priv->data->get_reset_line(reset_ctl); + if (!ptr_line) + return -EPERM; + + addr = priv->base + ptr_line->offset; + + dev_dbg(reset_ctl->dev, "reset id=%ld offset=0x%x bit=%d status=%d\n", + reset_ctl->id, ptr_line->offset, ptr_line->bit_idx, status); + + status = ptr_line->inverted ^ status; + + if (ptr_line->set_clr) { + if (!status) + addr += data->clear_offset; + + writel(BIT(ptr_line->bit_idx), addr); + + } else { + if (status) + setbits_le32(addr, BIT(ptr_line->bit_idx)); + else + clrbits_le32(addr, BIT(ptr_line->bit_idx)); + } + + /* Check deassert */ + if (!status) { + u32 reg; + + return readl_poll_timeout(addr, reg, + !(reg & BIT(ptr_line->bit_idx)), + data->reset_us); + } + + return 0; +} + +static int stm32_reset_assert(struct reset_ctl *reset_ctl) +{ + return stm32_reset_update(reset_ctl, true); +} + +static int stm32_reset_deassert(struct reset_ctl *reset_ctl) +{ + return stm32_reset_update(reset_ctl, false); +} + +const struct reset_ops stm32_reset_ops = { + .rst_assert = stm32_reset_assert, + .rst_deassert = stm32_reset_deassert, +}; + +int stm32_reset_core_probe(struct udevice *dev, + const struct stm32_reset_data *data) +{ + struct stm32_reset_priv *priv = dev_get_priv(dev); + + priv->base = dev_read_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) { + /* for MFD, get address of parent */ + priv->base = dev_read_addr(dev->parent); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL; + } + + priv->data = data; + + assert(priv->data); + + return 0; +} diff --git a/drivers/reset/stm32/stm32-reset-core.h b/drivers/reset/stm32/stm32-reset-core.h new file mode 100644 index 00000000000..25a1aa152cb --- /dev/null +++ b/drivers/reset/stm32/stm32-reset-core.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause */ +/* + * Copyright (C) 2025, STMicroelectronics - All Rights Reserved + * Author(s): Gabriel Fernandez, <gabriel.fernandez@foss.st.com> for STMicroelectronics. + */ + +#include <reset-uclass.h> + +struct stm32_reset_cfg { + u16 offset; + u8 bit_idx; + bool set_clr; + bool inverted; +}; + +struct stm32_reset_data { + const struct stm32_reset_cfg * (*get_reset_line)(struct reset_ctl *reset_ctl); + u32 clear_offset; + u32 reset_us; +}; + +struct stm32_reset_priv { + fdt_addr_t base; + struct stm32_reset_cfg reset_line; + const struct stm32_reset_data *data; +}; + +extern const struct reset_ops stm32_reset_ops; + +int stm32_reset_core_probe(struct udevice *dev, + const struct stm32_reset_data *data); diff --git a/drivers/reset/stm32/stm32-reset-mp1.c b/drivers/reset/stm32/stm32-reset-mp1.c new file mode 100644 index 00000000000..6863f6e64b7 --- /dev/null +++ b/drivers/reset/stm32/stm32-reset-mp1.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause +/* + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Author(s): Patrice Chotard, <patrice.chotard@foss.st.com> for STMicroelectronics. + */ + +#include <dm.h> +#include <stm32-reset-core.h> + +/* Reset clear offset for STM32MP RCC */ +#define RCC_CLR_OFFSET 0x4 + +/* Offset of register without set/clear management */ +#define RCC_MP_GCR_OFFSET 0x10C + +/* Timeout for deassert */ +#define STM32_DEASSERT_TIMEOUT_US 10000 + +static const struct stm32_reset_cfg *stm32_get_reset_line(struct reset_ctl *reset_ctl) +{ + struct stm32_reset_priv *priv = dev_get_priv(reset_ctl->dev); + struct stm32_reset_cfg *ptr_line = &priv->reset_line; + int bank = (reset_ctl->id / (sizeof(u32) * BITS_PER_BYTE)) * 4; + int offset = reset_ctl->id % (sizeof(u32) * BITS_PER_BYTE); + + ptr_line->offset = bank; + ptr_line->bit_idx = offset; + ptr_line->set_clr = true; + + if (ptr_line->offset == RCC_MP_GCR_OFFSET) { + ptr_line->set_clr = false; + ptr_line->inverted = true; + } + + return ptr_line; +} + +static const struct stm32_reset_data stm32mp1_reset_data = { + .get_reset_line = stm32_get_reset_line, + .clear_offset = RCC_CLR_OFFSET, + .reset_us = STM32_DEASSERT_TIMEOUT_US, +}; + +static int stm32_reset_probe(struct udevice *dev) +{ + return stm32_reset_core_probe(dev, &stm32mp1_reset_data); +} + +U_BOOT_DRIVER(stm32mp25_rcc_reset) = { + .name = "stm32mp1_reset", + .id = UCLASS_RESET, + .probe = stm32_reset_probe, + .priv_auto = sizeof(struct stm32_reset_priv), + .ops = &stm32_reset_ops, +}; diff --git a/drivers/reset/stm32/stm32-reset-mp25.c b/drivers/reset/stm32/stm32-reset-mp25.c new file mode 100644 index 00000000000..91c0336bc58 --- /dev/null +++ b/drivers/reset/stm32/stm32-reset-mp25.c @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause +/* + * Copyright (C) 2024, STMicroelectronics - All Rights Reserved + * Author(s): Gabriel Fernandez, <gabriel.fernandez@foss.st.com> for STMicroelectronics. + */ + +#include <dm.h> +#include <stm32-reset-core.h> +#include <stm32mp25_rcc.h> +#include <dt-bindings/reset/st,stm32mp25-rcc.h> + +/* Reset clear offset for STM32MP RCC */ +#define RCC_CLR_OFFSET 0x4 + +/* Timeout for deassert */ +#define STM32_DEASSERT_TIMEOUT_US 10000 + +#define RESET(id, _offset, _bit_idx, _set_clr) \ + [id] = &(struct stm32_reset_cfg){ \ + .offset = (_offset), \ + .bit_idx = (_bit_idx), \ + .set_clr = (_set_clr), \ + } + +static const struct stm32_reset_cfg *stm32mp25_reset[STM32MP25_LAST_RESET] = { + RESET(TIM1_R, RCC_TIM1CFGR, 0, 0), + RESET(TIM2_R, RCC_TIM2CFGR, 0, 0), + RESET(TIM3_R, RCC_TIM3CFGR, 0, 0), + RESET(TIM4_R, RCC_TIM4CFGR, 0, 0), + RESET(TIM5_R, RCC_TIM5CFGR, 0, 0), + RESET(TIM6_R, RCC_TIM6CFGR, 0, 0), + RESET(TIM7_R, RCC_TIM7CFGR, 0, 0), + RESET(TIM8_R, RCC_TIM8CFGR, 0, 0), + RESET(TIM10_R, RCC_TIM10CFGR, 0, 0), + RESET(TIM11_R, RCC_TIM11CFGR, 0, 0), + RESET(TIM12_R, RCC_TIM12CFGR, 0, 0), + RESET(TIM13_R, RCC_TIM13CFGR, 0, 0), + RESET(TIM14_R, RCC_TIM14CFGR, 0, 0), + RESET(TIM15_R, RCC_TIM15CFGR, 0, 0), + RESET(TIM16_R, RCC_TIM16CFGR, 0, 0), + RESET(TIM17_R, RCC_TIM17CFGR, 0, 0), + RESET(TIM20_R, RCC_TIM20CFGR, 0, 0), + RESET(LPTIM1_R, RCC_LPTIM1CFGR, 0, 0), + RESET(LPTIM2_R, RCC_LPTIM2CFGR, 0, 0), + RESET(LPTIM3_R, RCC_LPTIM3CFGR, 0, 0), + RESET(LPTIM4_R, RCC_LPTIM4CFGR, 0, 0), + RESET(LPTIM5_R, RCC_LPTIM5CFGR, 0, 0), + RESET(SPI1_R, RCC_SPI1CFGR, 0, 0), + RESET(SPI2_R, RCC_SPI2CFGR, 0, 0), + RESET(SPI3_R, RCC_SPI3CFGR, 0, 0), + RESET(SPI4_R, RCC_SPI4CFGR, 0, 0), + RESET(SPI5_R, RCC_SPI5CFGR, 0, 0), + RESET(SPI6_R, RCC_SPI6CFGR, 0, 0), + RESET(SPI7_R, RCC_SPI7CFGR, 0, 0), + RESET(SPI8_R, RCC_SPI8CFGR, 0, 0), + RESET(SPDIFRX_R, RCC_SPDIFRXCFGR, 0, 0), + RESET(USART1_R, RCC_USART1CFGR, 0, 0), + RESET(USART2_R, RCC_USART2CFGR, 0, 0), + RESET(USART3_R, RCC_USART3CFGR, 0, 0), + RESET(UART4_R, RCC_UART4CFGR, 0, 0), + RESET(UART5_R, RCC_UART5CFGR, 0, 0), + RESET(USART6_R, RCC_USART6CFGR, 0, 0), + RESET(UART7_R, RCC_UART7CFGR, 0, 0), + RESET(UART8_R, RCC_UART8CFGR, 0, 0), + RESET(UART9_R, RCC_UART9CFGR, 0, 0), + RESET(LPUART1_R, RCC_LPUART1CFGR, 0, 0), + RESET(IS2M_R, RCC_IS2MCFGR, 0, 0), + RESET(I2C1_R, RCC_I2C1CFGR, 0, 0), + RESET(I2C2_R, RCC_I2C2CFGR, 0, 0), + RESET(I2C3_R, RCC_I2C3CFGR, 0, 0), + RESET(I2C4_R, RCC_I2C4CFGR, 0, 0), + RESET(I2C5_R, RCC_I2C5CFGR, 0, 0), + RESET(I2C6_R, RCC_I2C6CFGR, 0, 0), + RESET(I2C7_R, RCC_I2C7CFGR, 0, 0), + RESET(I2C8_R, RCC_I2C8CFGR, 0, 0), + RESET(SAI1_R, RCC_SAI1CFGR, 0, 0), + RESET(SAI2_R, RCC_SAI2CFGR, 0, 0), + RESET(SAI3_R, RCC_SAI3CFGR, 0, 0), + RESET(SAI4_R, RCC_SAI4CFGR, 0, 0), + RESET(MDF1_R, RCC_MDF1CFGR, 0, 0), + RESET(MDF2_R, RCC_ADF1CFGR, 0, 0), + RESET(FDCAN_R, RCC_FDCANCFGR, 0, 0), + RESET(HDP_R, RCC_HDPCFGR, 0, 0), + RESET(ADC12_R, RCC_ADC12CFGR, 0, 0), + RESET(ADC3_R, RCC_ADC3CFGR, 0, 0), + RESET(ETH1_R, RCC_ETH1CFGR, 0, 0), + RESET(ETH2_R, RCC_ETH2CFGR, 0, 0), + RESET(USBH_R, RCC_USBHCFGR, 0, 0), + RESET(USB2PHY1_R, RCC_USB2PHY1CFGR, 0, 0), + RESET(USB2PHY2_R, RCC_USB2PHY2CFGR, 0, 0), + RESET(USB3DR_R, RCC_USB3DRCFGR, 0, 0), + RESET(USB3PCIEPHY_R, RCC_USB3PCIEPHYCFGR, 0, 0), + RESET(USBTC_R, RCC_UCPDCFGR, 0, 0), + RESET(ETHSW_R, RCC_ETHSWCFGR, 0, 0), + RESET(SDMMC1_R, RCC_SDMMC1CFGR, 0, 0), + RESET(SDMMC1DLL_R, RCC_SDMMC1CFGR, 16, 0), + RESET(SDMMC2_R, RCC_SDMMC2CFGR, 0, 0), + RESET(SDMMC2DLL_R, RCC_SDMMC2CFGR, 16, 0), + RESET(SDMMC3_R, RCC_SDMMC3CFGR, 0, 0), + RESET(SDMMC3DLL_R, RCC_SDMMC3CFGR, 16, 0), + RESET(GPU_R, RCC_GPUCFGR, 0, 0), + RESET(LTDC_R, RCC_LTDCCFGR, 0, 0), + RESET(DSI_R, RCC_DSICFGR, 0, 0), + RESET(LVDS_R, RCC_LVDSCFGR, 0, 0), + RESET(CSI_R, RCC_CSICFGR, 0, 0), + RESET(DCMIPP_R, RCC_DCMIPPCFGR, 0, 0), + RESET(CCI_R, RCC_CCICFGR, 0, 0), + RESET(VDEC_R, RCC_VDECCFGR, 0, 0), + RESET(VENC_R, RCC_VENCCFGR, 0, 0), + RESET(WWDG1_R, RCC_WWDG1CFGR, 0, 0), + RESET(WWDG2_R, RCC_WWDG2CFGR, 0, 0), + RESET(VREF_R, RCC_VREFCFGR, 0, 0), + RESET(DTS_R, RCC_DTSCFGR, 0, 0), + RESET(CRC_R, RCC_CRCCFGR, 0, 0), + RESET(SERC_R, RCC_SERCCFGR, 0, 0), + RESET(OSPIIOM_R, RCC_OSPIIOMCFGR, 0, 0), + RESET(I3C1_R, RCC_I3C1CFGR, 0, 0), + RESET(I3C2_R, RCC_I3C2CFGR, 0, 0), + RESET(I3C3_R, RCC_I3C3CFGR, 0, 0), + RESET(I3C4_R, RCC_I3C4CFGR, 0, 0), + RESET(IWDG2_KER_R, RCC_IWDGC1CFGSETR, 18, 1), + RESET(IWDG4_KER_R, RCC_IWDGC2CFGSETR, 18, 1), + RESET(RNG_R, RCC_RNGCFGR, 0, 0), + RESET(PKA_R, RCC_PKACFGR, 0, 0), + RESET(SAES_R, RCC_SAESCFGR, 0, 0), + RESET(HASH_R, RCC_HASHCFGR, 0, 0), + RESET(CRYP1_R, RCC_CRYP1CFGR, 0, 0), + RESET(CRYP2_R, RCC_CRYP2CFGR, 0, 0), + RESET(PCIE_R, RCC_PCIECFGR, 0, 0), +}; + +static const struct stm32_reset_cfg *stm32_get_reset_line(struct reset_ctl *reset_ctl) +{ + unsigned long id = reset_ctl->id; + + if (id < STM32MP25_LAST_RESET) + return stm32mp25_reset[id]; + + return NULL; +} + +static const struct stm32_reset_data stm32mp25_reset_data = { + .get_reset_line = stm32_get_reset_line, + .clear_offset = RCC_CLR_OFFSET, + .reset_us = STM32_DEASSERT_TIMEOUT_US, +}; + +static int stm32_reset_probe(struct udevice *dev) +{ + return stm32_reset_core_probe(dev, &stm32mp25_reset_data); +} + +U_BOOT_DRIVER(stm32mp25_rcc_reset) = { + .name = "stm32mp25_reset", + .id = UCLASS_RESET, + .probe = stm32_reset_probe, + .priv_auto = sizeof(struct stm32_reset_priv), + .ops = &stm32_reset_ops, +}; diff --git a/drivers/reset/stm32/stm32-reset.c b/drivers/reset/stm32/stm32-reset.c new file mode 100644 index 00000000000..975f67f712a --- /dev/null +++ b/drivers/reset/stm32/stm32-reset.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause +/* + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Author(s): Patrice Chotard, <patrice.chotard@foss.st.com> for STMicroelectronics. + */ + +#include <dm.h> +#include <stm32-reset-core.h> + +/* Timeout for deassert */ +#define STM32_DEASSERT_TIMEOUT_US 10000 + +static const struct stm32_reset_cfg *stm32_get_reset_line(struct reset_ctl *reset_ctl) +{ + struct stm32_reset_priv *priv = dev_get_priv(reset_ctl->dev); + struct stm32_reset_cfg *ptr_line = &priv->reset_line; + int bank = (reset_ctl->id / (sizeof(u32) * BITS_PER_BYTE)) * 4; + int offset = reset_ctl->id % (sizeof(u32) * BITS_PER_BYTE); + + ptr_line->offset = bank; + ptr_line->bit_idx = offset; + ptr_line->set_clr = true; + + return ptr_line; +} + +static const struct stm32_reset_data stm32_reset_data = { + .get_reset_line = stm32_get_reset_line, + .reset_us = STM32_DEASSERT_TIMEOUT_US, +}; + +static int stm32_reset_probe(struct udevice *dev) +{ + return stm32_reset_core_probe(dev, &stm32_reset_data); +} + +U_BOOT_DRIVER(stm32_rcc_reset) = { + .name = "stm32_rcc_reset", + .id = UCLASS_RESET, + .probe = stm32_reset_probe, + .priv_auto = sizeof(struct stm32_reset_priv), + .ops = &stm32_reset_ops, +}; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 6467f20422b..79b879d68d1 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -94,6 +94,13 @@ config RTC_DS1374 Support for Dallas Semiconductor (now Maxim) DS1374 and compatible Real Time Clock devices. +config RTC_DS1672 + bool "Enable DS1672 driver" + depends on DM_RTC + help + Support for Dallas Semiconductor (now Maxim) DS1672 compatible + Real Time Clock devices. + config RTC_DS3231 bool "Enable DS3231 driver" help diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 99b5a2a346a..a4ede413cd1 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_RTC_DS1307) += ds1307.o obj-$(CONFIG_RTC_DS1338) += ds1307.o obj-$(CONFIG_RTC_DS1337) += ds1337.o obj-$(CONFIG_RTC_DS1374) += ds1374.o +obj-$(CONFIG_RTC_DS1672) += ds1672.o obj-$(CONFIG_RTC_DS3231) += ds3231.o obj-$(CONFIG_RTC_DS3232) += ds3232.o obj-$(CONFIG_RTC_EMULATION) += emul_rtc.o diff --git a/drivers/rtc/ds1672.c b/drivers/rtc/ds1672.c new file mode 100644 index 00000000000..4705e5abc93 --- /dev/null +++ b/drivers/rtc/ds1672.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices DS1672 I2C RTC driver + * + * Copyright 2025 Gateworks Corporation. + */ +#include <dm.h> +#include <i2c.h> +#include <rtc.h> +#include <dm/device_compat.h> + +/* Registers */ +#define DS1672_REG_CNT_BASE 0 +#define DS1672_REG_CONTROL 4 +#define DS1672_REG_TRICKLE 5 + +#define DS1672_REG_CONTROL_EOSC 0x80 + +static int ds1672_read_time(struct udevice *dev, struct rtc_time *tm) +{ + time64_t secs; + u8 regs[4]; + int ret; + + ret = dm_i2c_read(dev, DS1672_REG_CONTROL, regs, 1); + if (ret) + return ret; + + if (regs[0] & DS1672_REG_CONTROL_EOSC) { + dev_err(dev, "Oscillator not enabled. Set time to enable.\n"); + return -EINVAL; + } + + ret = dm_i2c_read(dev, DS1672_REG_CNT_BASE, regs, 4); + if (ret) + return ret; + dev_dbg(dev, "raw read: 0x%02x 0x%02x 0x%02x 0x%02x\n", + regs[0], regs[1], regs[2], regs[3]); + secs = ((unsigned long)regs[3] << 24) | (regs[2] << 16) | (regs[1] << 8) | regs[0]; + rtc_to_tm(secs, tm); + + dev_dbg(dev, "read %lld %4d-%02d-%02d (wday=%d) %2d:%02d:%02d\n", secs, + tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); + + return 0; +} + +static int ds1672_set_time(struct udevice *dev, const struct rtc_time *tm) +{ + time64_t secs = rtc_mktime(tm); + u8 regs[5]; + + dev_dbg(dev, "set %4d-%02d-%02d (wday=%d) %2d:%02d:%02d %lld\n", + tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec, + secs); + + if (tm->tm_year < 2000) { + dev_err(dev, "year %d (before 2000) not supported\n", + tm->tm_year); + return -EINVAL; + } + + regs[0] = secs & 0x000000ff; + regs[1] = (secs & 0x0000ff00) >> 8; + regs[2] = (secs & 0x00ff0000) >> 16; + regs[3] = (secs & 0xff000000) >> 24; + regs[4] = 0; /* set control reg to enable counting */ + + return dm_i2c_write(dev, DS1672_REG_CNT_BASE, regs, 5); +} + +static int ds1672_reset(struct udevice *dev) +{ + u8 regs[5] = { 0 }; + + return dm_i2c_write(dev, DS1672_REG_CNT_BASE, regs, 5); +} + +static int ds1672_read8(struct udevice *dev, unsigned int reg) +{ + return dm_i2c_reg_read(dev, reg); +} + +static int ds1672_write8(struct udevice *dev, unsigned int reg, int val) +{ + return dm_i2c_reg_write(dev, reg, val); +} + +static const struct rtc_ops ds1672_rtc_ops = { + .get = ds1672_read_time, + .set = ds1672_set_time, + .reset = ds1672_reset, + .read8 = ds1672_read8, + .write8 = ds1672_write8, +}; + +static int ds1672_probe(struct udevice *dev) +{ + i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS | DM_I2C_CHIP_WR_ADDRESS); + + return 0; +} + +static const struct udevice_id ds1672_of_id[] = { + { .compatible = "dallas,ds1672" }, + { } +}; + +U_BOOT_DRIVER(rtc_max313xx) = { + .name = "rtc-ds1672", + .id = UCLASS_RTC, + .probe = ds1672_probe, + .of_match = ds1672_of_id, + .ops = &ds1672_rtc_ops, +}; diff --git a/drivers/serial/serial_mtk.c b/drivers/serial/serial_mtk.c index becf9317076..01cc415efdd 100644 --- a/drivers/serial/serial_mtk.c +++ b/drivers/serial/serial_mtk.c @@ -30,16 +30,23 @@ struct mtk_serial_regs { u32 mcr; u32 lsr; u32 msr; - u32 spr; - u32 mdr1; + u32 scr; + u32 autobaud_en; u32 highspeed; u32 sample_count; u32 sample_point; + u32 autobaud_reg; + u32 ratefix_ad; + u32 autobaud_sample; + u32 guard; + u32 escape_dat; + u32 escape_en; + u32 sleep_en; + u32 dma_en; + u32 rxtri_ad; u32 fracdiv_l; u32 fracdiv_m; - u32 escape_en; - u32 guard; - u32 rx_sel; + u32 fcr_rd; }; #define thr rbr @@ -92,10 +99,18 @@ struct mtk_serial_priv { bool upstream_highspeed_logic; }; +static const unsigned short fraction_l_mapping[] = { + 0, 1, 0x5, 0x15, 0x55, 0x57, 0x57, 0x77, 0x7F, 0xFF, 0xFF +}; + +static const unsigned short fraction_m_mapping[] = { + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3 +}; + static void _mtk_serial_setbrg(struct mtk_serial_priv *priv, int baud, uint clk_rate) { - u32 quot, realbaud, samplecount = 1; + u32 quot, realbaud, samplecount = 1, fraction, frac_l = 0, frac_m = 0; /* Special case for low baud clock */ if (baud <= 115200 && clk_rate == 12000000) { @@ -140,7 +155,13 @@ use_hs3: writel(3, &priv->regs->highspeed); quot = DIV_ROUND_UP(clk_rate, 256 * baud); - samplecount = DIV_ROUND_CLOSEST(clk_rate, quot * baud); + samplecount = clk_rate / (quot * baud); + + fraction = ((clk_rate * 100) / quot / baud) % 100; + fraction = DIV_ROUND_CLOSEST(fraction, 10); + + frac_l = fraction_l_mapping[fraction]; + frac_m = fraction_m_mapping[fraction]; } set_baud: @@ -152,7 +173,11 @@ set_baud: /* set highspeed mode sample count & point */ writel(samplecount - 1, &priv->regs->sample_count); - writel((samplecount - 2) >> 1, &priv->regs->sample_point); + writel((samplecount >> 1) - 1, &priv->regs->sample_point); + + /* set baudrate fraction compensation */ + writel(frac_l, &priv->regs->fracdiv_l); + writel(frac_m, &priv->regs->fracdiv_m); } static int _mtk_serial_putc(struct mtk_serial_priv *priv, const char ch) diff --git a/drivers/sound/max98088.h b/drivers/sound/max98088.h index b1307a73623..2ca6ca1f734 100644 --- a/drivers/sound/max98088.h +++ b/drivers/sound/max98088.h @@ -15,14 +15,14 @@ #define M98088_REG_JACK_STAUS 0x02 #define M98088_REG_BATTERY_VOLTAGE 0x03 #define M98088_REG_IRQ_ENABLE 0x0f -#define M98088_REG_SYS_CLK 0X10 +#define M98088_REG_SYS_CLK 0x10 #define M98088_REG_DAI1_CLKMODE 0x11 #define M98088_REG_DAI1_CLKCFG_HI 0x12 #define M98088_REG_DAI1_CLKCFG_LO 0x13 #define M98088_REG_DAI1_FORMAT 0x14 #define M98088_REG_DAI1_CLOCK 0x15 #define M98088_REG_DAI1_IOCFG 0x16 -#define M98088_REG_DAI1_TDM 0X17 +#define M98088_REG_DAI1_TDM 0x17 #define M98088_REG_DAI1_FILTERS 0x18 #define M98088_REG_DAI2_CLKMODE 0x19 #define M98088_REG_DAI2_CLKCFG_HI 0x1a @@ -30,10 +30,10 @@ #define M98088_REG_DAI2_FORMAT 0x1c #define M98088_REG_DAI2_CLOCK 0x1d #define M98088_REG_DAI2_IOCFG 0x1e -#define M98088_REG_DAI2_TDM 0X1f +#define M98088_REG_DAI2_TDM 0x1f #define M98088_REG_DAI2_FILTERS 0x20 -#define M98088_REG_SRC 0X21 -#define M98088_REG_MIX_DAC 0X22 +#define M98088_REG_SRC 0x21 +#define M98088_REG_MIX_DAC 0x22 #define M98088_REG_MIX_ADC_LEFT 0x23 #define M98088_REG_MIX_ADC_RIGHT 0x24 #define M98088_REG_MIX_HP_LEFT 0x25 @@ -50,37 +50,37 @@ #define M98088_REG_LVL_DAI1_PLAY_EQ 0x30 #define M98088_REG_LVL_DAI2_PLAY 0x31 #define M98088_REG_LVL_DAI2_PLAY_EQ 0x32 -#define M98088_REG_LVL_ADC_L 0X33 -#define M98088_REG_LVL_ADC_R 0X34 -#define M98088_REG_LVL_MIC1 0X35 -#define M98088_REG_LVL_MIC2 0X36 -#define M98088_REG_LVL_INA 0X37 -#define M98088_REG_LVL_INB 0X38 -#define M98088_REG_LVL_HP_L 0X39 -#define M98088_REG_LVL_HP_R 0X3a -#define M98088_REG_LVL_REC_L 0X3b -#define M98088_REG_LVL_REC_R 0X3c -#define M98088_REG_LVL_SPK_L 0X3d -#define M98088_REG_LVL_SPK_R 0X3e +#define M98088_REG_LVL_ADC_L 0x33 +#define M98088_REG_LVL_ADC_R 0x34 +#define M98088_REG_LVL_MIC1 0x35 +#define M98088_REG_LVL_MIC2 0x36 +#define M98088_REG_LVL_INA 0x37 +#define M98088_REG_LVL_INB 0x38 +#define M98088_REG_LVL_HP_L 0x39 +#define M98088_REG_LVL_HP_R 0x3a +#define M98088_REG_LVL_REC_L 0x3b +#define M98088_REG_LVL_REC_R 0x3c +#define M98088_REG_LVL_SPK_L 0x3d +#define M98088_REG_LVL_SPK_R 0x3e #define M98088_REG_MICAGC_CFG 0x3f #define M98088_REG_MICAGC_THRESH 0x40 -#define M98088_REG_SPKDHP 0X41 +#define M98088_REG_SPKDHP 0x41 #define M98088_REG_SPKDHP_THRESH 0x42 #define M98088_REG_SPKALC_COMP 0x43 #define M98088_REG_PWRLMT_CFG 0x44 #define M98088_REG_PWRLMT_TIME 0x45 #define M98088_REG_THDLMT_CFG 0x46 #define M98088_REG_CFG_AUDIO_IN 0x47 -#define M98088_REG_CFG_MIC 0X48 -#define M98088_REG_CFG_LEVEL 0X49 +#define M98088_REG_CFG_MIC 0x48 +#define M98088_REG_CFG_LEVEL 0x49 #define M98088_REG_CFG_BYPASS 0x4a #define M98088_REG_CFG_JACKDET 0x4b -#define M98088_REG_PWR_EN_IN 0X4c +#define M98088_REG_PWR_EN_IN 0x4c #define M98088_REG_PWR_EN_OUT 0x4d -#define M98088_REG_BIAS_CNTL 0X4e -#define M98088_REG_DAC_BIAS1 0X4f -#define M98088_REG_DAC_BIAS2 0X50 -#define M98088_REG_PWR_SYS 0X51 +#define M98088_REG_BIAS_CNTL 0x4e +#define M98088_REG_DAC_BIAS1 0x4f +#define M98088_REG_DAC_BIAS2 0x50 +#define M98088_REG_PWR_SYS 0x51 #define M98088_REG_DAI1_EQ_BASE 0x52 #define M98088_REG_DAI2_EQ_BASE 0x84 #define M98088_REG_DAI1_BIQUAD_BASE 0xb6 diff --git a/drivers/sound/max98095.h b/drivers/sound/max98095.h index 1521f3f02f9..009164d85d2 100644 --- a/drivers/sound/max98095.h +++ b/drivers/sound/max98095.h @@ -176,7 +176,7 @@ enum en_max_audio_interface { #define M98095_0FF_REV_ID 0xFF #define M98095_REG_CNT (0xFF+1) -#define M98095_REG_MAX_CACHED 0X97 +#define M98095_REG_MAX_CACHED 0x97 /* MAX98095 Registers Bit Fields */ diff --git a/drivers/tpm/tpm_tis_sandbox.c b/drivers/tpm/tpm_tis_sandbox.c index 2bc7dc87ed3..d7341062b31 100644 --- a/drivers/tpm/tpm_tis_sandbox.c +++ b/drivers/tpm/tpm_tis_sandbox.c @@ -221,6 +221,7 @@ static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, case 0x72: /* physical set deactivated */ case 0x99: /* startup */ case 0x50: /* self test full */ + case 0x53: /* self test continue */ case 0x4000000a: /* assert physical presence */ *recv_len = 12; memset(recvbuf, '\0', *recv_len); diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 86b2cbf3f6a..b3c780a4e35 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -228,7 +228,6 @@ static int write_fifo(struct at91_ep *ep, struct at91_request *req) } buf = req->req.buf + req->req.actual; - prefetch(buf); total = req->req.length - req->req.actual; if (ep->ep.maxpacket < total) { count = ep->ep.maxpacket; diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index f9326f0a7e7..72f68dba3a7 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -521,16 +521,16 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) static int usba_udc_pullup(struct usb_gadget *gadget, int is_on) { struct usba_udc *udc = to_usba_udc(gadget); - u32 ctrl; - - ctrl = usba_readl(udc, CTRL); + /* + * Some chips don't reliably drive DP/DM lines to high impedance when + * using the DETACH/PULLD_DIS bits. + * To ensure a reliable disconnect, power cycle the controller instead + */ if (is_on) - ctrl &= ~USBA_DETACH; + usba_writel(udc, CTRL, USBA_ENABLE_MASK); else - ctrl |= USBA_DETACH; - - usba_writel(udc, CTRL, ctrl); + usba_writel(udc, CTRL, USBA_DISABLE_MASK); return 0; } diff --git a/drivers/usb/gadget/f_sdp.c b/drivers/usb/gadget/f_sdp.c index 36934b1bcf7..647001d8dd0 100644 --- a/drivers/usb/gadget/f_sdp.c +++ b/drivers/usb/gadget/f_sdp.c @@ -863,7 +863,7 @@ static int sdp_handle_in_ep(struct spl_image_info *spl_image, struct spl_boot_device bootdev = {}; spl_parse_image_header(&spl_image, &bootdev, header); spl_board_prepare_for_boot(); - jump_to_image_no_args(&spl_image); + jump_to_image(&spl_image); #else /* In U-Boot, allow jumps to scripts */ cmd_source_script(sdp_func->jmp_address, NULL, NULL); diff --git a/drivers/usb/musb-new/musb_core.c b/drivers/usb/musb-new/musb_core.c index 6375be741ae..a14b127dc37 100644 --- a/drivers/usb/musb-new/musb_core.c +++ b/drivers/usb/musb-new/musb_core.c @@ -223,8 +223,6 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) struct musb *musb = hw_ep->musb; void __iomem *fifo = hw_ep->fifo; - prefetch((u8 *)src); - dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n", 'T', hw_ep->epnum, fifo, len, src); diff --git a/drivers/usb/musb-new/ti-musb.c b/drivers/usb/musb-new/ti-musb.c index ec1baa9337d..967d0953875 100644 --- a/drivers/usb/musb-new/ti-musb.c +++ b/drivers/usb/musb-new/ti-musb.c @@ -282,7 +282,6 @@ U_BOOT_DRIVER(ti_musb_peripheral) = { .ops = &ti_musb_gadget_ops, .probe = ti_musb_peripheral_probe, .remove = ti_musb_peripheral_remove, - .ops = &musb_usb_ops, .plat_auto = sizeof(struct ti_musb_plat), .priv_auto = sizeof(struct ti_musb_peripheral), .flags = DM_FLAG_PRE_RELOC, diff --git a/drivers/video/bridge/dp501.c b/drivers/video/bridge/dp501.c index 9937cfe095b..0ad589304aa 100644 --- a/drivers/video/bridge/dp501.c +++ b/drivers/video/bridge/dp501.c @@ -99,7 +99,7 @@ #define SD_DB15 0x4F /* Aux Channel and PCS */ -#define DPCD_REV 0X50 +#define DPCD_REV 0x50 #define MAX_LINK_RATE 0x51 #define MAX_LANE_COUNT 0x52 #define MAX_DOWNSPREAD 0x53 diff --git a/drivers/video/hx8238d.c b/drivers/video/hx8238d.c index 2491a32810e..f0220e4cc07 100644 --- a/drivers/video/hx8238d.c +++ b/drivers/video/hx8238d.c @@ -22,7 +22,7 @@ DECLARE_GLOBAL_DATA_PTR; #define HX8238D_OUTPUT_CTRL_ADDR 0x01 #define HX8238D_LCD_AC_CTRL_ADDR 0x02 #define HX8238D_POWER_CTRL_1_ADDR 0x03 -#define HX8238D_DATA_CLR_CTRL_ADDR 0X04 +#define HX8238D_DATA_CLR_CTRL_ADDR 0x04 #define HX8238D_FUNCTION_CTRL_ADDR 0x05 #define HX8238D_LED_CTRL_ADDR 0x08 #define HX8238D_CONT_BRIGHT_CTRL_ADDR 0x0A diff --git a/drivers/video/zynqmp/zynqmp_dpsub.h b/drivers/video/zynqmp/zynqmp_dpsub.h index 7d2737e31aa..dc549559cae 100644 --- a/drivers/video/zynqmp/zynqmp_dpsub.h +++ b/drivers/video/zynqmp/zynqmp_dpsub.h @@ -553,7 +553,7 @@ struct zynqmp_dpsub_priv { #define DPDMA_DESCRIPTOR_LINE_SIZE_STRIDE_SHIFT 18 #define DPDMA_DESCRIPTOR_SRC_ADDR_WIDTH 32U #define DPDMA_DESCRIPTOR_ADDR_EXT_SRC_ADDR_EXT_SHIFT 16U -#define DPDMA_CH0_DSCR_STRT_ADDR 0X0204U +#define DPDMA_CH0_DSCR_STRT_ADDR 0x0204U #define DPDMA_CH_OFFSET 0x100U #define DPDMA_CH0_CNTL 0x0218U #define DPDMA_CH3_CNTL 0x0518U diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 1bb67f50352..45eb9b4d3f9 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -29,6 +29,7 @@ config WATCHDOG_TIMEOUT_MSECS int "Watchdog timeout in msec" default 128000 if ARCH_MX31 || ARCH_MX5 || ARCH_MX6 default 128000 if ARCH_MX7 || ARCH_VF610 + default 30000 if ARCH_SNAPDRAGON default 30000 if ARCH_SOCFPGA default 16000 if ARCH_SUNXI default 5376 if ULP_WATCHDOG @@ -335,6 +336,22 @@ config WDT_K3_RTI_FW_FILE endif +config WDT_QCOM + bool "Qualcomm watchdog timer support" + depends on WDT && ARCH_SNAPDRAGON + imply WATCHDOG + help + Select this to enable Qualcomm watchdog timer, which can be found on + some Qualcomm chips. + +config WDT_RENESAS + bool "Renesas watchdog timer support" + depends on WDT && R8A779F0 + select CLK + select CLK_RENESAS + help + Enables Renesas SoC R8A779F0 watchdog timer support. + config WDT_SANDBOX bool "Enable Watchdog Timer support for Sandbox" depends on SANDBOX && WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index e6bd4c587af..d52d17e1c90 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_WDT_MTK) += mtk_wdt.o obj-$(CONFIG_WDT_NPCM) += npcm_wdt.o obj-$(CONFIG_WDT_OCTEONTX) += octeontx_wdt.o obj-$(CONFIG_WDT_OMAP3) += omap_wdt.o +obj-$(CONFIG_WDT_RENESAS) += renesas_wdt.o obj-$(CONFIG_WDT_SBSA) += sbsa_gwdt.o obj-$(CONFIG_WDT_K3_RTI) += rti_wdt.o obj-$(CONFIG_WDT_SIEMENS_PMIC) += siemens_pmic_wdt.o @@ -54,3 +55,4 @@ obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o obj-$(CONFIG_WDT_XILINX) += xilinx_wwdt.o obj-$(CONFIG_WDT_ADI) += adi_wdt.o +obj-$(CONFIG_WDT_QCOM) += qcom-wdt.o diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c index c809a8936b8..72e13787448 100644 --- a/drivers/watchdog/at91sam9_wdt.c +++ b/drivers/watchdog/at91sam9_wdt.c @@ -38,7 +38,7 @@ DECLARE_GLOBAL_DATA_PTR; */ static int at91_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) { - struct at91_wdt_priv *priv = dev_get_priv(dev); + struct at91_wdt_priv *wdt = dev_get_priv(dev); u64 timeout; u32 ticks; @@ -49,7 +49,7 @@ static int at91_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) ticks = WDT_SEC2TICKS(timeout); /* Check if disabled */ - if (readl(priv->regs + AT91_WDT_MR) & AT91_WDT_MR_WDDIS) { + if (readl(wdt->regs + AT91_WDT_MR) & wdt->wddis) { printf("sorry, watchdog is disabled\n"); return -1; } @@ -60,31 +60,41 @@ static int at91_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) * Since WDV is a 12-bit counter, the maximum period is * 4096 / 256 = 16 seconds. */ - priv->regval = AT91_WDT_MR_WDRSTEN /* causes watchdog reset */ - | AT91_WDT_MR_WDDBGHLT /* disabled in debug mode */ - | AT91_WDT_MR_WDD(0xfff) /* restart at any time */ - | AT91_WDT_MR_WDV(ticks); /* timer value */ - writel(priv->regval, priv->regs + AT91_WDT_MR); + + if (wdt->mode == AT91_WDT_MODE_SAM9260) { + wdt->mr = AT91_WDT_MR_WDRSTEN /* causes watchdog reset */ + | AT91_WDT_MR_WDDBGHLT /* disabled in debug mode */ + | AT91_WDT_MR_WDD(0xfff) /* restart at any time */ + | AT91_WDT_MR_WDV(ticks); /* timer value */ + writel(wdt->mr, wdt->regs + AT91_WDT_MR); + } else if (wdt->mode == AT91_WDT_MODE_SAM9X60) { + writel(AT91_SAM9X60_WLR_COUNTER(ticks), /* timer value */ + wdt->regs + AT91_SAM9X60_WLR); + + wdt->mr = AT91_SAM9X60_MR_PERIODRST /* causes watchdog reset */ + | AT91_SAM9X60_MR_WDDBGHLT; /* disabled in debug mode */ + writel(wdt->mr, wdt->regs + AT91_WDT_MR); + } return 0; } static int at91_wdt_stop(struct udevice *dev) { - struct at91_wdt_priv *priv = dev_get_priv(dev); + struct at91_wdt_priv *wdt = dev_get_priv(dev); /* Disable Watchdog Timer */ - priv->regval |= AT91_WDT_MR_WDDIS; - writel(priv->regval, priv->regs + AT91_WDT_MR); + wdt->mr |= wdt->wddis; + writel(wdt->mr, wdt->regs + AT91_WDT_MR); return 0; } static int at91_wdt_reset(struct udevice *dev) { - struct at91_wdt_priv *priv = dev_get_priv(dev); + struct at91_wdt_priv *wdt = dev_get_priv(dev); - writel(AT91_WDT_CR_WDRSTT | AT91_WDT_CR_KEY, priv->regs + AT91_WDT_CR); + writel(AT91_WDT_CR_WDRSTT | AT91_WDT_CR_KEY, wdt->regs + AT91_WDT_CR); return 0; } @@ -96,18 +106,31 @@ static const struct wdt_ops at91_wdt_ops = { }; static const struct udevice_id at91_wdt_ids[] = { - { .compatible = "atmel,at91sam9260-wdt" }, + { .compatible = "atmel,at91sam9260-wdt", + .data = AT91_WDT_MODE_SAM9260 }, + { .compatible = "atmel,sama5d4-wdt", + .data = AT91_WDT_MODE_SAM9260 }, + { .compatible = "microchip,sam9x60-wdt", + .data = AT91_WDT_MODE_SAM9X60 }, + { .compatible = "microchip,sama7g5-wdt", + .data = AT91_WDT_MODE_SAM9X60 }, {} }; static int at91_wdt_probe(struct udevice *dev) { - struct at91_wdt_priv *priv = dev_get_priv(dev); + struct at91_wdt_priv *wdt = dev_get_priv(dev); - priv->regs = dev_remap_addr(dev); - if (!priv->regs) + wdt->regs = dev_remap_addr(dev); + if (!wdt->regs) return -EINVAL; + wdt->mode = dev_get_driver_data(dev); + if (wdt->mode == AT91_WDT_MODE_SAM9260) + wdt->wddis = AT91_WDT_MR_WDDIS; + else if (wdt->mode == AT91_WDT_MODE_SAM9X60) + wdt->wddis = AT91_SAM9X60_MR_WDDIS; + debug("%s: Probing wdt%u\n", __func__, dev_seq(dev)); return 0; diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c new file mode 100644 index 00000000000..adbb5aacdc3 --- /dev/null +++ b/drivers/watchdog/qcom-wdt.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) Linaro Ltd. 2024 + * + * Authors: + * Casey Connolly <casey.connolly@linaro.org> + * Paul Sajna <hello@paulsajna.com> + * + * Derived from linux/drivers/watchdog/qcom-wdt.c + */ + +#include <dm.h> +#include <dm/device_compat.h> +#include <wdt.h> +#include <clk.h> + +#include <asm/io.h> + +enum wdt_reg { + WDT_RST, + WDT_EN, + WDT_STS, + WDT_BARK_TIME, + WDT_BITE_TIME, +}; + +struct qcom_wdt_match_data { + const u32 *offset; +}; + +struct qcom_wdt { + void __iomem *base; + ulong clk_rate; + const u32 *layout; +}; + +static const u32 reg_offset_data_kpss[] = { + [WDT_RST] = 0x4, + [WDT_EN] = 0x8, + [WDT_STS] = 0xC, + [WDT_BARK_TIME] = 0x10, + [WDT_BITE_TIME] = 0x14, +}; + +static const struct qcom_wdt_match_data match_data_kpss = { + .offset = reg_offset_data_kpss, +}; + +static void __iomem *wdt_addr(struct qcom_wdt *wdt, enum wdt_reg reg) +{ + return wdt->base + wdt->layout[reg]; +} + +int qcom_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct qcom_wdt *wdt = dev_get_priv(dev); + ulong bark_timeout_s = ((timeout_ms - 1) * wdt->clk_rate) / 1000; + ulong bite_timeout_s = (timeout_ms * wdt->clk_rate) / 1000; + + writel(0, wdt_addr(wdt, WDT_EN)); + writel(BIT(0), wdt_addr(wdt, WDT_RST)); + writel(bark_timeout_s, wdt_addr(wdt, WDT_BARK_TIME)); + writel(bite_timeout_s, wdt_addr(wdt, WDT_BITE_TIME)); + writel(BIT(0), wdt_addr(wdt, WDT_EN)); + if (readl(wdt_addr(wdt, WDT_EN)) != 1) { + dev_err(dev, "Failed to enable Qualcomm watchdog!\n"); + return -EIO; + } + return 0; +} + +int qcom_wdt_stop(struct udevice *dev) +{ + struct qcom_wdt *wdt = dev_get_priv(dev); + + writel(0, wdt_addr(wdt, WDT_EN)); + if (readl(wdt_addr(wdt, WDT_EN))) { + dev_err(dev, "Failed to disable Qualcomm watchdog!\n"); + return -EIO; + } + + return 0; +} + +int qcom_wdt_reset(struct udevice *dev) +{ + struct qcom_wdt *wdt = dev_get_priv(dev); + + writel(1, wdt_addr(wdt, WDT_RST)); + return 0; +} + +static int qcom_wdt_probe(struct udevice *dev) +{ + struct clk clk; + long rate; + int ret; + + struct qcom_wdt *wdt = dev_get_priv(dev); + struct qcom_wdt_match_data *data = (void *)dev_get_driver_data(dev); + + wdt->base = dev_read_addr_ptr(dev); + wdt->layout = data->offset; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + rate = clk_get_rate(&clk); + if (rate <= 0) + return rate < 0 ? (int)rate : -EINVAL; + + wdt->clk_rate = (ulong)rate; + + return 0; +} + +static const struct wdt_ops qcom_wdt_ops = { + .start = qcom_wdt_start, + .stop = qcom_wdt_stop, + .reset = qcom_wdt_reset, +}; + +static const struct udevice_id qcom_wdt_ids[] = { + { .compatible = "qcom,kpss-wdt", .data = (ulong)&match_data_kpss }, + {} +}; + +U_BOOT_DRIVER(qcom_wdt) = { + .name = "qcom_wdt", + .id = UCLASS_WDT, + .of_match = qcom_wdt_ids, + .ops = &qcom_wdt_ops, + .probe = qcom_wdt_probe, + .priv_auto = sizeof(struct qcom_wdt), +}; diff --git a/drivers/watchdog/renesas_wdt.c b/drivers/watchdog/renesas_wdt.c new file mode 100644 index 00000000000..046e11915b9 --- /dev/null +++ b/drivers/watchdog/renesas_wdt.c @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2025 Red Hat, Inc., Shmuel Leib Melamud <smelamud@redhat.com> + +#include <asm/io.h> +#include <clk.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <wdt.h> + +#define usleep_range(a, b) udelay((a)) + +struct rwdt { + u32 cnt; + u32 csra; + u32 csrb; +}; + +#define RWTCSRA_WOVF BIT(4) +#define RWTCSRA_WRFLG BIT(5) +#define RWTCSRA_TME BIT(7) + +#define CSR_MASK 0xA5A5A500 +#define CNT_MASK 0x5A5A0000 + +#define MAX_CNT_VALUE 65536 +/* + * In probe, clk_rate is checked to be not more than 16 bit * biggest clock + * divider (12 bits). d is only a factor to fully utilize the WDT counter and + * will not exceed its 16 bits. Thus, no overflow, we stay below 32 bits. + */ +#define MUL_BY_CLKS_PER_SEC(p, d) \ + DIV_ROUND_UP((d) * (p)->clk_rate, clk_divs[(p)->cks]) + +/* d is 16 bit, clk_divs 12 bit -> no 32 bit overflow */ +#define DIV_BY_CLKS_PER_SEC(p, d) ((d) * clk_divs[(p)->cks] / (p)->clk_rate) + +static const unsigned int clk_divs[] = { 1, 4, 16, 32, 64, 128, 1024, 4096 }; + +struct rwdt_priv { + struct rwdt __iomem *wdt; + unsigned long clk_rate; + u8 cks; + struct clk clk; +}; + +static void rwdt_wait_cycles(struct rwdt_priv *priv, unsigned int cycles) +{ + unsigned int delay; + + delay = DIV_ROUND_UP(cycles * 1000000, priv->clk_rate); + + usleep_range(delay, 2 * delay); +} + +static int rwdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + struct rwdt_priv *priv = dev_get_priv(dev); + u64 max_timeout; + u8 val; + + max_timeout = DIV_BY_CLKS_PER_SEC(priv, MAX_CNT_VALUE); + timeout = min(max_timeout, timeout / 1000); + + /* Stop the timer before we modify any register */ + val = readb_relaxed(&priv->wdt->csra) & ~RWTCSRA_TME; + writel_relaxed(val | CSR_MASK, &priv->wdt->csra); + /* Delay 2 cycles before setting watchdog counter */ + rwdt_wait_cycles(priv, 2); + + while (readb_relaxed(&priv->wdt->csra) & RWTCSRA_WRFLG) + cpu_relax(); + + writel_relaxed((MAX_CNT_VALUE - MUL_BY_CLKS_PER_SEC(priv, timeout)) + | CNT_MASK, &priv->wdt->cnt); + + writel_relaxed(priv->cks | RWTCSRA_TME | CSR_MASK, &priv->wdt->csra); + + return 0; +} + +static int rwdt_stop(struct udevice *dev) +{ + struct rwdt_priv *priv = dev_get_priv(dev); + + writel_relaxed(priv->cks | CSR_MASK, &priv->wdt->csra); + + return 0; +} + +static int rwdt_reset(struct udevice *dev) +{ + struct rwdt_priv *priv = dev_get_priv(dev); + u8 val; + + /* Stop the timer before we modify any register */ + val = readb_relaxed(&priv->wdt->csra) & ~RWTCSRA_TME; + writel_relaxed(val | CSR_MASK, &priv->wdt->csra); + /* Delay 2 cycles before setting watchdog counter */ + rwdt_wait_cycles(priv, 2); + + writel_relaxed(0xffff | CNT_MASK, &priv->wdt->cnt); + /* smallest divider to reboot soon */ + writel_relaxed(0 | CSR_MASK, &priv->wdt->csra); + + readb_poll_timeout(&priv->wdt->csra, val, !(val & RWTCSRA_WRFLG), 100); + + writel_relaxed(RWTCSRA_TME | CSR_MASK, &priv->wdt->csra); + + /* wait 2 cycles, so watchdog will trigger */ + rwdt_wait_cycles(priv, 2); + + return 0; +} + +static int rwdt_probe(struct udevice *dev) +{ + struct rwdt_priv *priv = dev_get_priv(dev); + unsigned long clks_per_sec; + int ret, i; + + priv->wdt = dev_remap_addr(dev); + if (!priv->wdt) + return -EINVAL; + + ret = clk_get_by_index(dev, 0, &priv->clk); + if (ret < 0) + return ret; + + ret = clk_enable(&priv->clk); + if (ret) + return ret; + + priv->clk_rate = clk_get_rate(&priv->clk); + if (!priv->clk_rate) { + ret = -ENOENT; + goto err_clk_disable; + } + + /* + * Find the largest possible divider that allows clock rate + * (clks_per_sec) to stay within 16 bits. In this case, we can still + * measure the smallest timeout (1s) and make the largest allowed + * timeout as large as possible. + */ + for (i = ARRAY_SIZE(clk_divs) - 1; i >= 0; i--) { + clks_per_sec = priv->clk_rate / clk_divs[i]; + if (clks_per_sec && clks_per_sec < 65536) { + priv->cks = i; + break; + } + } + + /* can't find a suitable clock divider */ + if (i < 0) { + ret = -ERANGE; + goto err_clk_disable; + } + + return 0; + +err_clk_disable: + clk_disable(&priv->clk); + + return ret; +} + +static const struct wdt_ops rwdt_ops = { + .start = rwdt_start, + .reset = rwdt_reset, + .stop = rwdt_stop, +}; + +static const struct udevice_id rwdt_ids[] = { + { .compatible = "renesas,rcar-gen2-wdt" }, + { .compatible = "renesas,rcar-gen3-wdt" }, + { .compatible = "renesas,rcar-gen4-wdt" }, + {} +}; + +U_BOOT_DRIVER(wdt_renesas) = { + .name = "wdt_renesas", + .id = UCLASS_WDT, + .of_match = rwdt_ids, + .ops = &rwdt_ops, + .probe = rwdt_probe, + .priv_auto = sizeof(struct rwdt_priv), +}; |