diff options
Diffstat (limited to 'drivers')
165 files changed, 10442 insertions, 2174 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/cache/Kconfig b/drivers/cache/Kconfig index 4f358657444..f5bcd406a50 100644 --- a/drivers/cache/Kconfig +++ b/drivers/cache/Kconfig @@ -24,6 +24,7 @@ config L2X0_CACHE config ANDES_L2_CACHE bool "Andes L2 cache driver" + depends on RISCV select CACHE help Support Andes L2 cache controller in AE350 platform. 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/Kconfig b/drivers/clk/imx/Kconfig index d17a54fb9b3..74d5fe73f94 100644 --- a/drivers/clk/imx/Kconfig +++ b/drivers/clk/imx/Kconfig @@ -14,6 +14,14 @@ config CLK_IMX6Q help This enables DM/DTS support for clock driver in i.MX6Q platforms. +config CLK_IMX6UL + bool "Clock support for i.MX6UL" + depends on ARCH_MX6 + select CLK + select CLK_CCF + help + This enables DM/DTS support for clock driver in i.MX6UL platforms. + config CLK_IMX8 bool "Clock support for i.MX8" depends on ARCH_IMX8 diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index a89ee7acb12..b10221a195c 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_$(PHASE_)CLK_CCF) += clk-gate2.o clk-pllv3.o clk-pfd.o obj-$(CONFIG_$(PHASE_)CLK_IMX6Q) += clk-imx6q.o +obj-$(CONFIG_$(PHASE_)CLK_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_CLK_IMX8) += clk-imx8.o ifdef CONFIG_CLK_IMX8 diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c index 81e19d393cf..b3926564a22 100644 --- a/drivers/clk/imx/clk-fracn-gppll.c +++ b/drivers/clk/imx/clk-fracn-gppll.c @@ -10,6 +10,7 @@ #include <dm/devres.h> #include <linux/bitfield.h> #include <linux/bitops.h> +#include <linux/bug.h> #include <linux/clk-provider.h> #include <linux/delay.h> #include <linux/err.h> diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c new file mode 100644 index 00000000000..32fb949ffbc --- /dev/null +++ b/drivers/clk/imx/clk-imx6ul.c @@ -0,0 +1,289 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Amarula Solutions Software Engineering + * Michael Trimarchi, Amarula Solutions Software Engineering, michael@amarulasolutions.com + */ + +#include <clk-uclass.h> +#include <dm.h> +#include <log.h> +#include <asm/arch/clock.h> +#include <asm/arch/imx-regs.h> +#include <dt-bindings/clock/imx6ul-clock.h> + +#include "clk.h" + +static int imx6ul_clk_request(struct clk *clk) +{ + debug("%s: request clk id %ld\n", __func__, clk->id); + + if (clk->id < IMX6UL_CLK_DUMMY || clk->id >= IMX6UL_CLK_END) { + printf("%s: Invalid clk ID #%lu\n", __func__, clk->id); + return -EINVAL; + } + + return 0; +} + +static struct clk_ops imx6ul_clk_ops = { + .request = imx6ul_clk_request, + .set_rate = ccf_clk_set_rate, + .get_rate = ccf_clk_get_rate, + .enable = ccf_clk_enable, + .disable = ccf_clk_disable, +}; + +static const char *const pll_bypass_src_sels[] = { "osc", "dummy", }; +static const char *const pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", }; +static const char *const bch_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *const gpmi_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; + +static const char *const enfc_sels[] = { "pll2_pfd0_352m", "pll2_bus", "pll3_usb_otg", "pll2_pfd2_396m", + "pll3_pfd3_454m", "dummy", "dummy", "dummy", }; +static const char *const usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *const periph_sels[] = { "periph_pre", "periph_clk2", }; +static const char *const periph2_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", + "pll4_audio_div", }; +static const char *const periph_clk2_sels[] = { "pll3_usb_otg", "osc", "pll2_bypass_src", }; +static const char *const periph2_clk2_sels[] = { "pll3_usb_otg", "osc", }; +static const char *const perclk_sels[] = { "ipg", "osc", }; + +static const char *const periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", + "pll2_198m", }; +static const char *const uart_sels[] = { "pll3_80m", "osc", }; +static const char *const ecspi_sels[] = { "pll3_60m", "osc", }; + +static int imx6ul_clk_probe(struct udevice *dev) +{ + struct clk osc_clk; + void *base; + int ret; + + /* Anatop clocks */ + base = (void *)ANATOP_BASE_ADDR; + + clk_dm(IMX6UL_CLK_DUMMY, clk_register_fixed_rate(NULL, "dummy", 0)); + + ret = clk_get_by_name(dev, "osc", &osc_clk); + if (ret) + return ret; + + clk_dm(IMX6UL_CLK_OSC, dev_get_clk_ptr(osc_clk.dev)); + + clk_dm(IMX6UL_CLK_PLL2, + imx_clk_pllv3(dev, IMX_PLLV3_GENERIC, "pll2_bus", "osc", + base + 0x30, 0x1)); + clk_dm(IMX6UL_CLK_PLL3, + imx_clk_pllv3(dev, IMX_PLLV3_USB, "pll3", "osc", + base + 0x10, 0x3)); + clk_dm(IMX6UL_PLL3_BYPASS_SRC, + imx_clk_mux(dev, "pll3_bypass_src", base + 0x10, 14, 1, + pll_bypass_src_sels, + ARRAY_SIZE(pll_bypass_src_sels))); + clk_dm(IMX6UL_PLL3_BYPASS, + imx_clk_mux_flags(dev, "pll3_bypass", base + 0x10, 16, 1, + pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX6UL_CLK_PLL3_USB_OTG, + imx_clk_gate(dev, "pll3_usb_otg", "pll3_bypass", base + 0x10, + 13)); + clk_dm(IMX6UL_CLK_PLL3_80M, + imx_clk_fixed_factor(dev, "pll3_80m", "pll3_usb_otg", 1, 6)); + clk_dm(IMX6UL_CLK_PLL3_60M, + imx_clk_fixed_factor(dev, "pll3_60m", "pll3_usb_otg", 1, 8)); + clk_dm(IMX6UL_CLK_PLL2_PFD0, + imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0)); + clk_dm(IMX6UL_CLK_PLL2_PFD1, + imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1)); + clk_dm(IMX6UL_CLK_PLL2_PFD2, + imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2)); + clk_dm(IMX6UL_CLK_PLL2_PFD3, + imx_clk_pfd("pll2_pfd3_396m", "pll2_bus", base + 0x100, 3)); + clk_dm(IMX6UL_CLK_PLL6, + imx_clk_pllv3(dev, IMX_PLLV3_ENET, "pll6", "osc", base + 0xe0, + 0x3)); + clk_dm(IMX6UL_CLK_PLL6_ENET, + imx_clk_gate(dev, "pll6_enet", "pll6", base + 0xe0, 13)); + + /* CCM clocks */ + base = dev_read_addr_ptr(dev); + if (!base) + return -EINVAL; + + clk_dm(IMX6UL_CLK_GPMI_SEL, + imx_clk_mux(dev, "gpmi_sel", base + 0x1c, 19, 1, gpmi_sels, + ARRAY_SIZE(gpmi_sels))); + clk_dm(IMX6UL_CLK_BCH_SEL, + imx_clk_mux(dev, "bch_sel", base + 0x1c, 18, 1, bch_sels, + ARRAY_SIZE(bch_sels))); + clk_dm(IMX6UL_CLK_USDHC1_SEL, + imx_clk_mux(dev, "usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, + ARRAY_SIZE(usdhc_sels))); + clk_dm(IMX6UL_CLK_USDHC2_SEL, + imx_clk_mux(dev, "usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, + ARRAY_SIZE(usdhc_sels))); + clk_dm(IMX6UL_CLK_ECSPI_SEL, + imx_clk_mux(dev, "ecspi_sel", base + 0x38, 18, 1, ecspi_sels, + ARRAY_SIZE(ecspi_sels))); + clk_dm(IMX6UL_CLK_UART_SEL, + imx_clk_mux(dev, "uart_sel", base + 0x24, 6, 1, uart_sels, + ARRAY_SIZE(uart_sels))); + clk_dm(IMX6UL_CLK_ENFC_SEL, + imx_clk_mux(dev, "enfc_sel", base + 0x2c, 15, 3, enfc_sels, + ARRAY_SIZE(enfc_sels))); + clk_dm(IMX6UL_CLK_PERCLK_SEL, + imx_clk_mux(dev, "perclk_sel", base + 0x1c, 6, 1, perclk_sels, + ARRAY_SIZE(perclk_sels))); + clk_dm(IMX6UL_CLK_PERIPH_PRE, + imx_clk_mux(dev, "periph_pre", base + 0x18, 18, 2, + periph_pre_sels, ARRAY_SIZE(periph_pre_sels))); + clk_dm(IMX6UL_CLK_PERIPH2_PRE, + imx_clk_mux(dev, "periph2_pre", base + 0x18, 21, 2, + periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels))); + clk_dm(IMX6UL_CLK_PERIPH_CLK2_SEL, + imx_clk_mux(dev, "periph_clk2_sel", base + 0x18, 12, 2, + periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels))); + clk_dm(IMX6UL_CLK_PERIPH2_CLK2_SEL, + imx_clk_mux(dev, "periph2_clk2_sel", base + 0x18, 20, 1, + periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels))); + clk_dm(IMX6UL_CLK_PERIPH, + imx_clk_busy_mux(dev, "periph", base + 0x14, 25, 1, base + 0x48, + 5, periph_sels, ARRAY_SIZE(periph_sels))); + clk_dm(IMX6UL_CLK_AHB, + imx_clk_busy_divider(dev, "ahb", "periph", base + 0x14, 10, 3, + base + 0x48, 1)); + clk_dm(IMX6UL_CLK_PERIPH_CLK2, + imx_clk_divider(dev, "periph_clk2", "periph_clk2_sel", + base + 0x14, 27, 3)); + clk_dm(IMX6UL_CLK_PERIPH2_CLK2, + imx_clk_divider(dev, "periph2_clk2", "periph2_clk2_sel", + base + 0x14, 0, 3)); + clk_dm(IMX6UL_CLK_IPG, + imx_clk_divider(dev, "ipg", "ahb", base + 0x14, 8, 2)); + clk_dm(IMX6UL_CLK_ENFC_PRED, + imx_clk_divider(dev, "enfc_pred", "enfc_sel", base + 0x2c, 18, + 3)); + clk_dm(IMX6UL_CLK_ENFC_PODF, + imx_clk_divider(dev, "enfc_podf", "enfc_pred", base + 0x2c, 21, + 6)); + clk_dm(IMX6UL_CLK_GPMI_PODF, + imx_clk_divider(dev, "gpmi_podf", "gpmi_sel", base + 0x24, 22, + 3)); + clk_dm(IMX6UL_CLK_BCH_PODF, + imx_clk_divider(dev, "bch_podf", "bch_sel", base + 0x24, 19, 3)); + clk_dm(IMX6UL_CLK_PERCLK, + imx_clk_divider(dev, "perclk", "perclk_sel", base + 0x1c, 0, 6)); + clk_dm(IMX6UL_CLK_UART_PODF, + imx_clk_divider(dev, "uart_podf", "uart_sel", base + 0x24, 0, + 6)); + clk_dm(IMX6UL_CLK_USDHC1_PODF, + imx_clk_divider(dev, "usdhc1_podf", "usdhc1_sel", base + 0x24, + 11, 3)); + clk_dm(IMX6UL_CLK_USDHC2_PODF, + imx_clk_divider(dev, "usdhc2_podf", "usdhc2_sel", base + 0x24, + 16, 3)); + clk_dm(IMX6UL_CLK_ECSPI_PODF, + imx_clk_divider(dev, "ecspi_podf", "ecspi_sel", base + 0x38, 19, + 6)); + + clk_dm(IMX6UL_CLK_APBHDMA, + imx_clk_gate2(dev, "apbh_dma", "bch_podf", base + 0x68, 4)); + clk_dm(IMX6UL_CLK_ECSPI1, + imx_clk_gate2(dev, "ecspi1", "ecspi_podf", base + 0x6c, 0)); + clk_dm(IMX6UL_CLK_ECSPI2, + imx_clk_gate2(dev, "ecspi2", "ecspi_podf", base + 0x6c, 2)); + clk_dm(IMX6UL_CLK_ECSPI3, + imx_clk_gate2(dev, "ecspi3", "ecspi_podf", base + 0x6c, 4)); + clk_dm(IMX6UL_CLK_ECSPI4, + imx_clk_gate2(dev, "ecspi4", "ecspi_podf", base + 0x6c, 6)); + + clk_dm(IMX6UL_CLK_USBOH3, + imx_clk_gate2(dev, "usboh3", "ipg", base + 0x80, 0)); + clk_dm(IMX6UL_CLK_USDHC1, + imx_clk_gate2(dev, "usdhc1", "usdhc1_podf", base + 0x80, 2)); + clk_dm(IMX6UL_CLK_USDHC2, + imx_clk_gate2(dev, "usdhc2", "usdhc2_podf", base + 0x80, 4)); + + clk_dm(IMX6UL_CLK_UART1_IPG, + imx_clk_gate2(dev, "uart1_ipg", "ipg", base + 0x7c, 24)); + clk_dm(IMX6UL_CLK_UART1_SERIAL, + imx_clk_gate2(dev, "uart1_serial", "uart_podf", base + 0x7c, 24)); + clk_dm(IMX6UL_CLK_UART2_IPG, + imx_clk_gate2(dev, "uart2_ipg", "ipg", base + 0x68, 28)); + clk_dm(IMX6UL_CLK_UART2_SERIAL, + imx_clk_gate2(dev, "uart2_serial", "uart_podf", base + 0x68, 28)); + clk_dm(IMX6UL_CLK_UART3_IPG, + imx_clk_gate2(dev, "uart3_ipg", "ipg", base + 0x6c, 10)); + clk_dm(IMX6UL_CLK_UART3_SERIAL, + imx_clk_gate2(dev, "uart3_serial", "uart_podf", base + 0x6c, 10)); + clk_dm(IMX6UL_CLK_UART4_IPG, + imx_clk_gate2(dev, "uart4_ipg", "ipg", base + 0x6c, 24)); + clk_dm(IMX6UL_CLK_UART4_SERIAL, + imx_clk_gate2(dev, "uart4_serial", "uart_podf", base + 0x6c, 24)); + clk_dm(IMX6UL_CLK_UART5_IPG, + imx_clk_gate2(dev, "uart5_ipg", "ipg", base + 0x74, 2)); + clk_dm(IMX6UL_CLK_UART5_SERIAL, + imx_clk_gate2(dev, "uart5_serial", "uart_podf", base + 0x74, 2)); + clk_dm(IMX6UL_CLK_UART6_IPG, + imx_clk_gate2(dev, "uart6_ipg", "ipg", base + 0x74, 6)); + clk_dm(IMX6UL_CLK_UART6_SERIAL, + imx_clk_gate2(dev, "uart6_serial", "uart_podf", base + 0x74, 6)); + clk_dm(IMX6UL_CLK_UART7_IPG, + imx_clk_gate2(dev, "uart7_ipg", "ipg", base + 0x7c, 26)); + clk_dm(IMX6UL_CLK_UART7_SERIAL, + imx_clk_gate2(dev, "uart7_serial", "uart_podf", base + 0x7c, 26)); + clk_dm(IMX6UL_CLK_UART8_IPG, + imx_clk_gate2(dev, "uart8_ipg", "ipg", base + 0x80, 14)); + clk_dm(IMX6UL_CLK_UART8_SERIAL, + imx_clk_gate2(dev, "uart8_serial", "uart_podf", base + 0x80, 14)); + +#if CONFIG_IS_ENABLED(NAND_MXS) + clk_dm(IMX6UL_CLK_PER_BCH, + imx_clk_gate2(dev, "per_bch", "bch_podf", base + 0x78, 12)); + clk_dm(IMX6UL_CLK_GPMI_BCH_APB, + imx_clk_gate2(dev, "gpmi_bch_apb", "bch_podf", base + 0x78, 24)); + clk_dm(IMX6UL_CLK_GPMI_BCH, + imx_clk_gate2(dev, "gpmi_bch", "gpmi_podf", base + 0x78, 26)); + clk_dm(IMX6UL_CLK_GPMI_IO, + imx_clk_gate2(dev, "gpmi_io", "enfc_podf", base + 0x78, 28)); + clk_dm(IMX6UL_CLK_GPMI_APB, + imx_clk_gate2(dev, "gpmi_apb", "bch_podf", base + 0x78, 30)); +#endif + + clk_dm(IMX6UL_CLK_I2C1, + imx_clk_gate2(dev, "i2c1", "perclk", base + 0x70, 6)); + clk_dm(IMX6UL_CLK_I2C2, + imx_clk_gate2(dev, "i2c2", "perclk", base + 0x70, 8)); + clk_dm(IMX6UL_CLK_I2C3, + imx_clk_gate2(dev, "i2c3", "perclk", base + 0x70, 10)); + clk_dm(IMX6UL_CLK_PWM1, + imx_clk_gate2(dev, "pwm1", "perclk", base + 0x78, 16)); + + clk_dm(IMX6UL_CLK_ENET, + imx_clk_gate2(dev, "enet", "ipg", base + 0x6c, 10)); + clk_dm(IMX6UL_CLK_ENET_REF, + imx_clk_fixed_factor(dev, "enet_ref", "pll6_enet", 1, 1)); + + struct clk *clk, *clk1; + + clk_get_by_id(IMX6UL_CLK_ENFC_SEL, &clk); + clk_get_by_id(IMX6UL_CLK_PLL2_PFD2, &clk1); + + clk_set_parent(clk, clk1); + + return 0; +} + +static const struct udevice_id imx6ul_clk_ids[] = { + { .compatible = "fsl,imx6ul-ccm" }, + { }, +}; + +U_BOOT_DRIVER(imx6ul_clk) = { + .name = "clk_imx6ul", + .id = UCLASS_CLK, + .of_match = imx6ul_clk_ids, + .ops = &imx6ul_clk_ops, + .probe = imx6ul_clk_probe, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/mediatek/clk-mt7981.c b/drivers/clk/mediatek/clk-mt7981.c index 60814652322..6130c93d5e6 100644 --- a/drivers/clk/mediatek/clk-mt7981.c +++ b/drivers/clk/mediatek/clk-mt7981.c @@ -566,7 +566,7 @@ U_BOOT_DRIVER(mtk_clk_apmixedsys) = { .of_match = mt7981_fixed_pll_compat, .probe = mt7981_fixed_pll_probe, .priv_auto = sizeof(struct mtk_clk_priv), - .ops = &mtk_clk_topckgen_ops, + .ops = &mtk_clk_fixed_pll_ops, .flags = DM_FLAG_PRE_RELOC, }; diff --git a/drivers/clk/mediatek/clk-mt7986.c b/drivers/clk/mediatek/clk-mt7986.c index f9d6f9c1749..cf298af644c 100644 --- a/drivers/clk/mediatek/clk-mt7986.c +++ b/drivers/clk/mediatek/clk-mt7986.c @@ -573,7 +573,7 @@ U_BOOT_DRIVER(mtk_clk_apmixedsys) = { .of_match = mt7986_fixed_pll_compat, .probe = mt7986_fixed_pll_probe, .priv_auto = sizeof(struct mtk_clk_priv), - .ops = &mtk_clk_topckgen_ops, + .ops = &mtk_clk_fixed_pll_ops, .flags = DM_FLAG_PRE_RELOC, }; diff --git a/drivers/clk/mediatek/clk-mt7987.c b/drivers/clk/mediatek/clk-mt7987.c index 173686a38e8..b662d680b15 100644 --- a/drivers/clk/mediatek/clk-mt7987.c +++ b/drivers/clk/mediatek/clk-mt7987.c @@ -67,7 +67,7 @@ U_BOOT_DRIVER(mtk_clk_apmixedsys) = { .of_match = mt7987_fixed_pll_compat, .probe = mt7987_fixed_pll_probe, .priv_auto = sizeof(struct mtk_clk_priv), - .ops = &mtk_clk_topckgen_ops, + .ops = &mtk_clk_fixed_pll_ops, .flags = DM_FLAG_PRE_RELOC, }; diff --git a/drivers/clk/mediatek/clk-mt7988.c b/drivers/clk/mediatek/clk-mt7988.c index 73fd9c6bea6..c6da42f970b 100644 --- a/drivers/clk/mediatek/clk-mt7988.c +++ b/drivers/clk/mediatek/clk-mt7988.c @@ -830,7 +830,7 @@ U_BOOT_DRIVER(mtk_clk_apmixedsys) = { .of_match = mt7988_fixed_pll_compat, .probe = mt7988_fixed_pll_probe, .priv_auto = sizeof(struct mtk_clk_priv), - .ops = &mtk_clk_topckgen_ops, + .ops = &mtk_clk_fixed_pll_ops, .flags = DM_FLAG_PRE_RELOC, }; diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c index 66683aeb2d7..f91777e968a 100644 --- a/drivers/clk/mediatek/clk-mtk.c +++ b/drivers/clk/mediatek/clk-mtk.c @@ -47,6 +47,11 @@ static int mtk_clk_get_id(struct clk *clk) return id; } +static int mtk_dummy_enable(struct clk *clk) +{ + return 0; +} + static int mtk_gate_enable(void __iomem *base, const struct mtk_gate *gate) { u32 bit = BIT(gate->shift); @@ -752,6 +757,12 @@ const struct clk_ops mtk_clk_apmixedsys_ops = { .get_rate = mtk_apmixedsys_get_rate, }; +const struct clk_ops mtk_clk_fixed_pll_ops = { + .enable = mtk_dummy_enable, + .disable = mtk_dummy_enable, + .get_rate = mtk_topckgen_get_rate, +}; + const struct clk_ops mtk_clk_topckgen_ops = { .enable = mtk_clk_mux_enable, .disable = mtk_clk_mux_disable, diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index c1d9901c10b..4ef1341aea6 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -283,6 +283,7 @@ struct mtk_cg_priv { }; extern const struct clk_ops mtk_clk_apmixedsys_ops; +extern const struct clk_ops mtk_clk_fixed_pll_ops; extern const struct clk_ops mtk_clk_topckgen_ops; extern const struct clk_ops mtk_clk_infrasys_ops; extern const struct clk_ops mtk_clk_gate_ops; diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 3ea01f3c969..34e41461e72 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -31,6 +31,14 @@ config CLK_QCOM_IPQ4019 on the Snapdragon IPQ4019 SoC. This driver supports the clocks and resets exposed by the GCC hardware block. +config CLK_QCOM_IPQ5424 + bool "Qualcomm IPQ5424 GCC" + select CLK_QCOM + help + Say Y here to enable support for the Global Clock Controller + on the Qualcomm IPQ5424 SoC. This driver supports the clocks + and resets exposed by the GCC hardware block. + config CLK_QCOM_IPQ9574 bool "Qualcomm IPQ9574 GCC" select CLK_QCOM @@ -55,6 +63,22 @@ config CLK_QCOM_QCS404 on the Snapdragon QCS404 SoC. This driver supports the clocks and resets exposed by the GCC hardware block. +config CLK_QCOM_QCS615 + bool "Qualcomm QCS615 GCC" + select CLK_QCOM + help + Say Y here to enable support for the Global Clock Controller + on the Snapdragon QCS615 SoC. This driver supports the clocks + and resets exposed by the GCC hardware block. + +config CLK_QCOM_QCS8300 + bool "Qualcomm QCS8300 GCC" + select CLK_QCOM + help + Say Y here to enable support for the Global Clock Controller + on the Snapdragon QCS8300 SoC. This driver supports the clocks + and resets exposed by the GCC hardware block. + config CLK_QCOM_SA8775P bool "Qualcomm SA8775 GCC" select CLK_QCOM diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index e13fc8c1071..b3d95b0faa3 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -7,9 +7,12 @@ obj-$(CONFIG_CLK_QCOM_SDM845) += clock-sdm845.o obj-$(CONFIG_CLK_QCOM_APQ8016) += clock-apq8016.o obj-$(CONFIG_CLK_QCOM_APQ8096) += clock-apq8096.o obj-$(CONFIG_CLK_QCOM_IPQ4019) += clock-ipq4019.o +obj-$(CONFIG_CLK_QCOM_IPQ5424) += clock-ipq5424.o obj-$(CONFIG_CLK_QCOM_IPQ9574) += clock-ipq9574.o obj-$(CONFIG_CLK_QCOM_QCM2290) += clock-qcm2290.o obj-$(CONFIG_CLK_QCOM_QCS404) += clock-qcs404.o +obj-$(CONFIG_CLK_QCOM_QCS8300) += clock-qcs8300.o +obj-$(CONFIG_CLK_QCOM_QCS615) += clock-qcs615.o obj-$(CONFIG_CLK_QCOM_SA8775P) += clock-sa8775p.o obj-$(CONFIG_CLK_QCOM_SC7280) += clock-sc7280.o obj-$(CONFIG_CLK_QCOM_SM6115) += clock-sm6115.o diff --git a/drivers/clk/qcom/clock-ipq5424.c b/drivers/clk/qcom/clock-ipq5424.c new file mode 100644 index 00000000000..40823a30ead --- /dev/null +++ b/drivers/clk/qcom/clock-ipq5424.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Clock drivers for Qualcomm ipq5424 + * + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <clk-uclass.h> +#include <dm.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <linux/bug.h> +#include <linux/bitops.h> +#include <dt-bindings/clock/qcom,ipq5424-gcc.h> +#include <dt-bindings/reset/qcom,ipq5424-gcc.h> + +#include "clock-qcom.h" + +#define GCC_IM_SLEEP_CBCR 0x1834020u + +static ulong ipq5424_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + switch (clk->id) { + case GCC_QUPV3_UART1_CLK: + clk_rcg_set_rate_mnd(priv->base, priv->data->clks[clk->id].reg, + 0, 144, 15625, CFG_CLK_SRC_GPLL0, 16); + return rate; + case GCC_SDCC1_APPS_CLK: + clk_rcg_set_rate_mnd(priv->base, priv->data->clks[clk->id].reg, + 5, 0, 0, CFG_CLK_SRC_GPLL2_MAIN, 16); + return rate; + } + return 0; +} + +static const struct gate_clk ipq5424_clks[] = { + GATE_CLK(GCC_QUPV3_UART1_CLK, 0x302c, BIT(0)), + GATE_CLK(GCC_SDCC1_AHB_CLK, 0x3303c, BIT(0)), + GATE_CLK(GCC_SDCC1_APPS_CLK, 0x33004, BIT(1)), + GATE_CLK(GCC_IM_SLEEP_CLK, 0x34020, BIT(0)), +}; + +static int ipq5424_enable(struct clk *clk) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + if (clk->id >= ARRAY_SIZE(ipq5424_clks) || !ipq5424_clks[clk->id].reg) + return -EINVAL; + + qcom_gate_clk_en(priv, clk->id); + + return 0; +} + +static const struct qcom_reset_map ipq5424_gcc_resets[] = { + [GCC_SDCC_BCR] = { 0x33000 }, +}; + +static struct msm_clk_data ipq5424_gcc_data = { + .resets = ipq5424_gcc_resets, + .num_resets = ARRAY_SIZE(ipq5424_gcc_resets), + .clks = ipq5424_clks, + .num_clks = ARRAY_SIZE(ipq5424_clks), + + .enable = ipq5424_enable, + .set_rate = ipq5424_set_rate, +}; + +static const struct udevice_id gcc_ipq5424_of_match[] = { + { + .compatible = "qcom,ipq5424-gcc", + .data = (ulong)&ipq5424_gcc_data, + }, + { } +}; + +static int ipq5424_clk_probe(struct udevice *dev) +{ + /* Enable the sleep clock needed for the MMC block reset */ + writel(BIT(0), GCC_IM_SLEEP_CBCR); + + return 0; +} + +U_BOOT_DRIVER(gcc_ipq5424) = { + .name = "gcc_ipq5424", + .id = UCLASS_NOP, + .of_match = gcc_ipq5424_of_match, + .probe = ipq5424_clk_probe, + .bind = qcom_cc_bind, + .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF, +}; diff --git a/drivers/clk/qcom/clock-qcom.h b/drivers/clk/qcom/clock-qcom.h index 1b60882dae4..3a4550d8536 100644 --- a/drivers/clk/qcom/clock-qcom.h +++ b/drivers/clk/qcom/clock-qcom.h @@ -13,6 +13,7 @@ #define CFG_CLK_SRC_GPLL0 (1 << 8) #define CFG_CLK_SRC_GPLL0_AUX2 (2 << 8) #define CFG_CLK_SRC_GPLL2 (2 << 8) +#define CFG_CLK_SRC_GPLL2_MAIN (2 << 8) #define CFG_CLK_SRC_GPLL9 (2 << 8) #define CFG_CLK_SRC_GPLL0_ODD (3 << 8) #define CFG_CLK_SRC_GPLL6 (4 << 8) diff --git a/drivers/clk/qcom/clock-qcs615.c b/drivers/clk/qcom/clock-qcs615.c new file mode 100644 index 00000000000..4700baba8c9 --- /dev/null +++ b/drivers/clk/qcom/clock-qcs615.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Clock drivers for Qualcomm qcs615 + * + * (C) Copyright 2024 Linaro Ltd. + */ + +#include <linux/types.h> +#include <clk-uclass.h> +#include <dm.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <linux/bug.h> +#include <linux/bitops.h> +#include <dt-bindings/clock/qcom,qcs615-gcc.h> +#include "clock-qcom.h" + +#define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf034 +#define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf01c +#define USB3_PRIM_PHY_AUX_CMD_RCGR 0xf060 + +#define GCC_QUPV3_WRAP0_S0_CLK_ENA_BIT BIT(10) +#define GCC_QUPV3_WRAP0_S1_CLK_ENA_BIT BIT(11) +#define GCC_QUPV3_WRAP0_S2_CLK_ENA_BIT BIT(12) +#define GCC_QUPV3_WRAP0_S3_CLK_ENA_BIT BIT(13) +#define GCC_QUPV3_WRAP0_S4_CLK_ENA_BIT BIT(14) +#define GCC_QUPV3_WRAP0_S5_CLK_ENA_BIT BIT(15) + +#define GCC_QUPV3_WRAP1_S0_CLK_ENA_BIT BIT(22) +#define GCC_QUPV3_WRAP1_S1_CLK_ENA_BIT BIT(23) +#define GCC_QUPV3_WRAP1_S2_CLK_ENA_BIT BIT(24) +#define GCC_QUPV3_WRAP1_S3_CLK_ENA_BIT BIT(25) +#define GCC_QUPV3_WRAP1_S4_CLK_ENA_BIT BIT(26) +#define GCC_QUPV3_WRAP1_S5_CLK_ENA_BIT BIT(27) + +static ulong qcs615_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + if (clk->id < priv->data->num_clks) + debug("%s: %s, requested rate=%ld\n", __func__, + priv->data->clks[clk->id].name, rate); + + switch (clk->id) { + case GCC_USB30_PRIM_MOCK_UTMI_CLK: + WARN(rate != 19200000, "Unexpected rate for USB30_PRIM_MOCK_UTMI_CLK: %lu\n", rate); + clk_rcg_set_rate(priv->base, USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR, 0, CFG_CLK_SRC_CXO); + return rate; + case GCC_USB30_PRIM_MASTER_CLK: + WARN(rate != 200000000, "Unexpected rate for USB30_PRIM_MASTER_CLK: %lu\n", rate); + clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR, + 5, 0, 0, CFG_CLK_SRC_GPLL0, 8); + clk_rcg_set_rate(priv->base, USB3_PRIM_PHY_AUX_CMD_RCGR, 0, 0); + return rate; + default: + return 0; + } +} + +static const struct gate_clk qcs615_clks[] = { + GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0xf078, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0xf010, BIT(0)), + GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0xf07c, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0xf014, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0xf018, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0xf050, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0xf054, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0xf058, BIT(0)), + GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x5200c, GCC_QUPV3_WRAP0_S0_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x5200c, GCC_QUPV3_WRAP0_S1_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP0_S2_CLK, 0x5200c, GCC_QUPV3_WRAP0_S2_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP0_S3_CLK, 0x5200c, GCC_QUPV3_WRAP0_S3_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP0_S4_CLK, 0x5200c, GCC_QUPV3_WRAP0_S4_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP0_S5_CLK, 0x5200c, GCC_QUPV3_WRAP0_S5_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP1_S0_CLK, 0x5200c, GCC_QUPV3_WRAP1_S0_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP1_S1_CLK, 0x5200c, GCC_QUPV3_WRAP1_S1_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP1_S2_CLK, 0x5200c, GCC_QUPV3_WRAP1_S2_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP1_S3_CLK, 0x5200c, GCC_QUPV3_WRAP1_S3_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP1_S4_CLK, 0x5200c, GCC_QUPV3_WRAP1_S4_CLK_ENA_BIT), + GATE_CLK(GCC_QUPV3_WRAP1_S5_CLK, 0x5200c, GCC_QUPV3_WRAP1_S5_CLK_ENA_BIT), + GATE_CLK(GCC_DISP_HF_AXI_CLK, 0xb038, BIT(0)), + GATE_CLK(GCC_DISP_AHB_CLK, 0xb032, BIT(0)) +}; + +static int qcs615_enable(struct clk *clk) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + if (priv->data->num_clks < clk->id) { + debug("%s: unknown clk id %lu\n", __func__, clk->id); + return 0; + } + + debug("%s: clk %ld: %s\n", __func__, clk->id, qcs615_clks[clk->id].name); + + switch (clk->id) { + case GCC_AGGRE_USB3_PRIM_AXI_CLK: + qcom_gate_clk_en(priv, GCC_USB30_PRIM_MASTER_CLK); + fallthrough; + case GCC_USB30_PRIM_MASTER_CLK: + qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_AUX_CLK); + qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_COM_AUX_CLK); + break; + } + + qcom_gate_clk_en(priv, clk->id); + + return 0; +} + +static const struct qcom_reset_map qcs615_gcc_resets[] = { + [GCC_EMAC_BCR] = { 0x6000 }, + [GCC_QUSB2PHY_PRIM_BCR] = { 0xd000 }, + [GCC_QUSB2PHY_SEC_BCR] = { 0xd004 }, + [GCC_USB30_PRIM_BCR] = { 0xf000 }, + [GCC_USB2_PHY_SEC_BCR] = { 0x50018 }, + [GCC_USB3_DP_PHY_SEC_BCR] = { 0x50020 }, + [GCC_USB3PHY_PHY_SEC_BCR] = { 0x5001c }, + [GCC_PCIE_0_BCR] = { 0x6b000 }, + [GCC_PCIE_0_PHY_BCR] = { 0x6c01c }, + [GCC_PCIE_PHY_BCR] = { 0x6f000 }, + [GCC_PCIE_PHY_COM_BCR] = { 0x6f010 }, + [GCC_UFS_PHY_BCR] = { 0x77000 }, + [GCC_USB20_SEC_BCR] = { 0xa6000 }, + [GCC_USB3PHY_PHY_PRIM_SP0_BCR] = { 0x50008 }, + [GCC_USB3_PHY_PRIM_SP0_BCR] = { 0x50000 }, + [GCC_SDCC1_BCR] = { 0x12000 }, + [GCC_SDCC2_BCR] = { 0x14000 } +}; + +static const struct qcom_power_map qcs615_gdscs[] = { + [UFS_PHY_GDSC] = { 0x77004 }, + [USB30_PRIM_GDSC] = { 0xf004 }, +}; + +static struct msm_clk_data sa8775_gcc_data = { + .resets = qcs615_gcc_resets, + .num_resets = ARRAY_SIZE(qcs615_gcc_resets), + .clks = qcs615_clks, + .num_clks = ARRAY_SIZE(qcs615_clks), + + .power_domains = qcs615_gdscs, + .num_power_domains = ARRAY_SIZE(qcs615_gdscs), + + .enable = qcs615_enable, + .set_rate = qcs615_set_rate, +}; + +static const struct udevice_id gcc_qcs615_of_match[] = { + { + .compatible = "qcom,qcs615-gcc", + .data = (ulong)&sa8775_gcc_data, + }, + { } +}; + +U_BOOT_DRIVER(gcc_qcs615) = { + .name = "gcc_qcs615", + .id = UCLASS_NOP, + .of_match = gcc_qcs615_of_match, + .bind = qcom_cc_bind, + .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF, +}; diff --git a/drivers/clk/qcom/clock-qcs8300.c b/drivers/clk/qcom/clock-qcs8300.c new file mode 100644 index 00000000000..cd8aecdf788 --- /dev/null +++ b/drivers/clk/qcom/clock-qcs8300.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024-2025, Qualcomm Innovation Center, Inc. All rights reserved. + * + */ + +#include <linux/types.h> +#include <clk-uclass.h> +#include <dm.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <linux/bug.h> +#include <linux/bitops.h> +#include <dt-bindings/clock/qcom,qcs8300-gcc.h> +#include "clock-qcom.h" + +#define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf038 +#define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf020 + +static ulong qcs8300_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + if (clk->id < priv->data->num_clks) + debug("%s: %s, requested rate=%ld\n", + __func__, priv->data->clks[clk->id].name, rate); + + switch (clk->id) { + case GCC_USB30_PRIM_MOCK_UTMI_CLK: + WARN(rate != 19200000, "Unexpected rate for USB30_PRIM_MOCK_UTMI_CLK: %lu\n", rate); + clk_rcg_set_rate(priv->base, USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR, 0, CFG_CLK_SRC_CXO); + return rate; + case GCC_USB30_PRIM_MASTER_CLK: + WARN(rate != 200000000, "Unexpected rate for USB30_PRIM_MASTER_CLK: %lu\n", rate); + clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR, + 1, 0, 0, CFG_CLK_SRC_GPLL0_ODD, 8); + clk_rcg_set_rate(priv->base, 0xf064, 0, 0); + return rate; + default: + return 0; + } +} + +static const struct gate_clk qcs8300_clks[] = { + GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x1b088, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0x1b018, BIT(0)), + GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x1b084, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0x1b020, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0x1b024, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0x1b05c, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0x1b060, BIT(0)), + GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x83020, BIT(0)), + GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x83018, BIT(0)), + GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x830d4, BIT(0)), + GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x83064, BIT(0)), +}; + +static int qcs8300_enable(struct clk *clk) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + if (priv->data->num_clks < clk->id) { + debug("%s: unknown clk id %lu\n", __func__, clk->id); + return 0; + } + + debug("%s: clk %ld: %s\n", __func__, clk->id, qcs8300_clks[clk->id].name); + + switch (clk->id) { + case GCC_AGGRE_USB3_PRIM_AXI_CLK: + qcom_gate_clk_en(priv, GCC_USB30_PRIM_MASTER_CLK); + fallthrough; + case GCC_USB30_PRIM_MASTER_CLK: + qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_AUX_CLK); + qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_COM_AUX_CLK); + break; + } + + qcom_gate_clk_en(priv, clk->id); + + return 0; +} + +static const struct qcom_reset_map qcs8300_gcc_resets[] = { + [GCC_EMAC0_BCR] = { 0xb6000 }, + [GCC_PCIE_0_BCR] = { 0xa9000 }, + [GCC_PCIE_0_LINK_DOWN_BCR] = { 0xbf000 }, + [GCC_PCIE_0_NOCSR_COM_PHY_BCR] = { 0xbf008 }, + [GCC_PCIE_0_PHY_BCR] = { 0xa9144 }, + [GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR] = { 0xbf00c }, + [GCC_PCIE_1_BCR] = { 0x77000 }, + [GCC_PCIE_1_LINK_DOWN_BCR] = { 0xae084 }, + [GCC_PCIE_1_NOCSR_COM_PHY_BCR] = { 0xae090 }, + [GCC_PCIE_1_PHY_BCR] = { 0xae08c }, + [GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR] = { 0xae094 }, + [GCC_SDCC1_BCR] = { 0x20000 }, + [GCC_UFS_PHY_BCR] = { 0x83000 }, + [GCC_USB20_PRIM_BCR] = { 0x1c000 }, + [GCC_USB2_PHY_PRIM_BCR] = { 0x5c01c }, + [GCC_USB2_PHY_SEC_BCR] = { 0x5c020 }, + [GCC_USB30_PRIM_BCR] = { 0x1b000 }, + [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x5c008 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0x5c000 }, + [GCC_USB3_PHY_TERT_BCR] = { 0x5c024 }, + [GCC_USB3_UNIPHY_MP0_BCR] = { 0x5c00c }, + [GCC_USB3_UNIPHY_MP1_BCR] = { 0x5c010 }, + [GCC_USB3PHY_PHY_PRIM_BCR] = { 0x5c004 }, + [GCC_USB3UNIPHY_PHY_MP0_BCR] = { 0x5c014 }, + [GCC_USB3UNIPHY_PHY_MP1_BCR] = { 0x5c018 }, + [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x76000 }, + [GCC_VIDEO_BCR] = { 0x34000 }, +}; + +static const struct qcom_power_map qcs8300_gdscs[] = { + [GCC_UFS_PHY_GDSC] = { 0x83004 }, + [GCC_USB30_PRIM_GDSC] = { 0x1B004 }, +}; + +static struct msm_clk_data qcs8300_gcc_data = { + .resets = qcs8300_gcc_resets, + .num_resets = ARRAY_SIZE(qcs8300_gcc_resets), + .clks = qcs8300_clks, + .num_clks = ARRAY_SIZE(qcs8300_clks), + + .power_domains = qcs8300_gdscs, + .num_power_domains = ARRAY_SIZE(qcs8300_gdscs), + + .enable = qcs8300_enable, + .set_rate = qcs8300_set_rate, +}; + +static const struct udevice_id gcc_qcs8300_of_match[] = { + { + .compatible = "qcom,qcs8300-gcc", + .data = (ulong)&qcs8300_gcc_data, + }, + { } +}; + +U_BOOT_DRIVER(gcc_qcs8300) = { + .name = "gcc_qcs8300", + .id = UCLASS_NOP, + .of_match = gcc_qcs8300_of_match, + .bind = qcom_cc_bind, + .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF, +}; diff --git a/drivers/clk/qcom/clock-sc7280.c b/drivers/clk/qcom/clock-sc7280.c index 9aff8a847ad..47e0ca5f0e5 100644 --- a/drivers/clk/qcom/clock-sc7280.c +++ b/drivers/clk/qcom/clock-sc7280.c @@ -205,7 +205,7 @@ static const char *const sc7280_rcg_names[] = { "GCC_PCIE_1_AUX_CLK_SRC", }; -static struct msm_clk_data qcs404_gcc_data = { +static struct msm_clk_data sc7280_gcc_data = { .resets = sc7280_gcc_resets, .num_resets = ARRAY_SIZE(sc7280_gcc_resets), .clks = sc7280_clks, @@ -225,7 +225,7 @@ static struct msm_clk_data qcs404_gcc_data = { static const struct udevice_id gcc_sc7280_of_match[] = { { .compatible = "qcom,gcc-sc7280", - .data = (ulong)&qcs404_gcc_data, + .data = (ulong)&sc7280_gcc_data, }, { } }; diff --git a/drivers/clk/qcom/clock-sm8250.c b/drivers/clk/qcom/clock-sm8250.c index 26396847d85..cc481258d22 100644 --- a/drivers/clk/qcom/clock-sm8250.c +++ b/drivers/clk/qcom/clock-sm8250.c @@ -360,7 +360,7 @@ static const char *const sm8250_rcg_names[] = { "GCC_PCIE_2_AUX_CMD_RCGR", }; -static struct msm_clk_data qcs404_gcc_data = { +static struct msm_clk_data sm8250_gcc_data = { .resets = sm8250_gcc_resets, .num_resets = ARRAY_SIZE(sm8250_gcc_resets), .clks = sm8250_clks, @@ -381,7 +381,7 @@ static struct msm_clk_data qcs404_gcc_data = { static const struct udevice_id gcc_sm8250_of_match[] = { { .compatible = "qcom,gcc-sm8250", - .data = (ulong)&qcs404_gcc_data, + .data = (ulong)&sm8250_gcc_data, }, {} }; diff --git a/drivers/clk/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/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_scsi.c b/drivers/dfu/dfu_scsi.c index 7ec34a8f7e3..d99b05d23ac 100644 --- a/drivers/dfu/dfu_scsi.c +++ b/drivers/dfu/dfu_scsi.c @@ -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/fwu-mdata/raw_mtd.c b/drivers/fwu-mdata/raw_mtd.c index 78a709f766c..41c153038ab 100644 --- a/drivers/fwu-mdata/raw_mtd.c +++ b/drivers/fwu-mdata/raw_mtd.c @@ -8,6 +8,7 @@ #include <fwu.h> #include <fwu_mdata.h> #include <memalign.h> +#include <mtd.h> #include <linux/errno.h> #include <linux/types.h> 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/gpio/pca953x.c b/drivers/gpio/pca953x.c index 2fb14590c0f..f0a79b92b02 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -13,6 +13,7 @@ #include <i2c.h> #include <pca953x.h> #include <vsprintf.h> +#include <asm/byteorder.h> /* Default to an address that hopefully won't corrupt other i2c devices */ #ifndef CFG_SYS_I2C_PCA953X_ADDR 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/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/mmc.c b/drivers/mmc/mmc.c index cdcf2e0c8fe..2c1f4f9c336 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -20,6 +20,7 @@ #include <linux/bitops.h> #include <linux/delay.h> #include <linux/printk.h> +#include <linux/sizes.h> #include <power/regulator.h> #include <malloc.h> #include <memalign.h> @@ -3277,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/rpmb.c b/drivers/mmc/rpmb.c index fa3ac2d9e37..8bfdffd56f5 100644 --- a/drivers/mmc/rpmb.c +++ b/drivers/mmc/rpmb.c @@ -11,7 +11,7 @@ #include <log.h> #include <memalign.h> #include <mmc.h> -#include <sdhci.h> +#include <asm/byteorder.h> #include <u-boot/sha256.h> #include "mmc_private.h" @@ -91,7 +91,6 @@ static int mmc_rpmb_request(struct mmc *mmc, const struct s_rpmb *s, { struct mmc_cmd cmd = {0}; struct mmc_data data; - struct sdhci_host *host = mmc->priv; int ret; ret = mmc_set_blockcount(mmc, count, is_rel_write); @@ -106,9 +105,6 @@ static int mmc_rpmb_request(struct mmc *mmc, const struct s_rpmb *s, cmd.cmdarg = 0; cmd.resp_type = MMC_RSP_R1; - if (host->quirks & SDHCI_QUIRK_BROKEN_R1B) - cmd.resp_type = MMC_RSP_R1; - data.src = (const char *)s; data.blocks = 1; data.blocksize = MMC_MAX_BLOCK_LEN; 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/snps_sdhci.c b/drivers/mmc/snps_sdhci.c index f5ede38c3c1..fe834ec2969 100644 --- a/drivers/mmc/snps_sdhci.c +++ b/drivers/mmc/snps_sdhci.c @@ -6,6 +6,7 @@ #include <clk.h> #include <dm.h> #include <linux/bitfield.h> +#include <linux/sizes.h> #include <sdhci.h> /* DWCMSHC specific Mode Select value */ diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c index 9dc1ceaa09b..3b86bc9b18c 100644 --- a/drivers/mmc/socfpga_dw_mmc.c +++ b/drivers/mmc/socfpga_dw_mmc.c @@ -54,16 +54,30 @@ static int socfpga_dwmci_clksel(struct dwmci_host *host) u32 sdmmc_mask = ((priv->smplsel & 0x7) << SYSMGR_SDMMC_SMPLSEL_SHIFT) | ((priv->drvsel & 0x7) << SYSMGR_SDMMC_DRVSEL_SHIFT); + /* Get clock manager base address */ + struct udevice *clkmgr_dev; + int ret = uclass_get_device_by_name(UCLASS_CLK, "clock-controller@ffd10000", &clkmgr_dev); + + if (ret) { + printf("Failed to get clkmgr device: %d\n", ret); + return ret; + } + + fdt_addr_t clkmgr_base = dev_read_addr(clkmgr_dev); + + if (clkmgr_base == FDT_ADDR_T_NONE) { + printf("Failed to read base address from clkmgr DT node\n"); + return -EINVAL; + } + /* Disable SDMMC clock. */ - clrbits_le32(socfpga_get_clkmgr_addr() + CLKMGR_PERPLL_EN, + clrbits_le32(clkmgr_base + CLKMGR_PERPLL_EN, CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); debug("%s: drvsel %d smplsel %d\n", __func__, priv->drvsel, priv->smplsel); #if !defined(CONFIG_XPL_BUILD) && defined(CONFIG_SPL_ATF) - int ret; - ret = socfpga_secure_reg_write32(SOCFPGA_SECURE_REG_SYSMGR_SOC64_SDMMC, sdmmc_mask); if (ret) { @@ -78,7 +92,7 @@ static int socfpga_dwmci_clksel(struct dwmci_host *host) #endif /* Enable SDMMC clock */ - setbits_le32(socfpga_get_clkmgr_addr() + CLKMGR_PERPLL_EN, + setbits_le32(clkmgr_base + CLKMGR_PERPLL_EN, CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); return 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/altera_qspi.c b/drivers/mtd/altera_qspi.c index e5c8df750b7..46174aab349 100644 --- a/drivers/mtd/altera_qspi.c +++ b/drivers/mtd/altera_qspi.c @@ -9,10 +9,10 @@ #include <fdt_support.h> #include <flash.h> #include <log.h> -#include <mtd.h> #include <asm/global_data.h> #include <asm/io.h> #include <linux/bitops.h> +#include <linux/mtd/mtd.h> DECLARE_GLOBAL_DATA_PTR; 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/raw/mxs_nand.c b/drivers/mtd/nand/raw/mxs_nand.c index 80d9307cdd1..ba67466069b 100644 --- a/drivers/mtd/nand/raw/mxs_nand.c +++ b/drivers/mtd/nand/raw/mxs_nand.c @@ -1507,8 +1507,18 @@ static void mxs_compute_timings(struct nand_chip *chip, writel(GPMI_CTRL1_CLEAR_MASK, &nand_info->gpmi_regs->hw_gpmi_ctrl1_clr); writel(ctrl1n, &nand_info->gpmi_regs->hw_gpmi_ctrl1_set); + /* Clock dividers do NOT guarantee a clean clock signal on its output + * during the change of the divide factor on i.MX6Q/UL/SX. On i.MX7/8, + * all clock dividers provide these guarantee. + */ + if (IS_ENABLED(CONFIG_MX6ULL)) + clk_disable(nand_info->gpmi_clk); + clk_set_rate(nand_info->gpmi_clk, clk_rate); + if (IS_ENABLED(CONFIG_MX6ULL)) + clk_enable(nand_info->gpmi_clk); + /* Wait 64 clock cycles before using the GPMI after enabling the DLL */ dll_wait_time_us = USEC_PER_SEC / clk_rate * 64; if (!dll_wait_time_us) diff --git a/drivers/mtd/nand/raw/mxs_nand_dt.c b/drivers/mtd/nand/raw/mxs_nand_dt.c index 11dbcbbf442..90eefa2558d 100644 --- a/drivers/mtd/nand/raw/mxs_nand_dt.c +++ b/drivers/mtd/nand/raw/mxs_nand_dt.c @@ -99,10 +99,8 @@ static int mxs_nand_dt_probe(struct udevice *dev) info->use_minimum_ecc = dev_read_bool(dev, "fsl,use-minimum-ecc"); if (IS_ENABLED(CONFIG_CLK) && - (IS_ENABLED(CONFIG_IMX8) || IS_ENABLED(CONFIG_IMX8M))) { - /* Assigned clock already set clock */ - struct clk gpmi_clk; - + (IS_ENABLED(CONFIG_IMX8) || IS_ENABLED(CONFIG_IMX8M) || IS_ENABLED(CONFIG_MX6ULL))) { + struct clk_bulk clk_bulk; info->gpmi_clk = devm_clk_get(dev, "gpmi_io"); if (IS_ERR(info->gpmi_clk)) { @@ -111,47 +109,11 @@ static int mxs_nand_dt_probe(struct udevice *dev) return ret; } - ret = clk_enable(info->gpmi_clk); - if (ret < 0) { - debug("Can't enable gpmi io clk: %d\n", ret); - return ret; - } - - if (IS_ENABLED(CONFIG_IMX8)) { - ret = clk_get_by_name(dev, "gpmi_apb", &gpmi_clk); - if (ret < 0) { - debug("Can't get gpmi_apb clk: %d\n", ret); - return ret; - } - - ret = clk_enable(&gpmi_clk); - if (ret < 0) { - debug("Can't enable gpmi_apb clk: %d\n", ret); - return ret; - } - - ret = clk_get_by_name(dev, "gpmi_bch", &gpmi_clk); - if (ret < 0) { - debug("Can't get gpmi_bch clk: %d\n", ret); - return ret; - } - - ret = clk_enable(&gpmi_clk); - if (ret < 0) { - debug("Can't enable gpmi_bch clk: %d\n", ret); - return ret; - } - } - - ret = clk_get_by_name(dev, "gpmi_bch_apb", &gpmi_clk); - if (ret < 0) { - debug("Can't get gpmi_bch_apb clk: %d\n", ret); - return ret; - } - - ret = clk_enable(&gpmi_clk); + ret = clk_get_bulk(dev, &clk_bulk); + if (!ret) + ret = clk_enable_bulk(&clk_bulk); if (ret < 0) { - debug("Can't enable gpmi_bch_apb clk: %d\n", ret); + debug("Can't enable gpmi clks: %d\n", ret); return ret; } } diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c index f2ecf47f8d4..fe8c76acac6 100644 --- a/drivers/mtd/nand/spi/gigadevice.c +++ b/drivers/mtd/nand/spi/gigadevice.c @@ -43,6 +43,22 @@ static SPINAND_OP_VARIANTS(read_cache_variants_f, SPINAND_PAGE_READ_FROM_CACHE_OP_3A(true, 0, 1, NULL, 0), SPINAND_PAGE_READ_FROM_CACHE_OP_3A(false, 0, 0, NULL, 0)); +static SPINAND_OP_VARIANTS(read_cache_variants_1gq5, + SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + +static SPINAND_OP_VARIANTS(read_cache_variants_2gq5, + SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 4, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 2, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + static SPINAND_OP_VARIANTS(write_cache_variants, SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), SPINAND_PROG_LOAD(true, 0, NULL, 0)); @@ -329,6 +345,36 @@ static const struct spinand_info gigadevice_spinand_table[] = { SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, gd5fxgq4uexxg_ecc_get_status)), + SPINAND_INFO("GD5F1GQ4RExxG", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xc1), + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq4uexxg_ecc_get_status)), + SPINAND_INFO("GD5F2GQ4UExxG", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd2), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq4uexxg_ecc_get_status)), + SPINAND_INFO("GD5F2GQ4RExxG", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xc2), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq4uexxg_ecc_get_status)), SPINAND_INFO("GD5F1GQ4UFxxG", SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb1, 0x48), NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), @@ -343,12 +389,152 @@ static const struct spinand_info gigadevice_spinand_table[] = { SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x51), NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(4, 512), - SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq5xexxg_ecc_get_status)), + SPINAND_INFO("GD5F1GQ5RExxG", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x41), + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(4, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq5xexxg_ecc_get_status)), + SPINAND_INFO("GD5F2GQ5UExxG", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x52), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(4, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq5xexxg_ecc_get_status)), + SPINAND_INFO("GD5F2GQ5RExxG", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x42), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(4, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq5xexxg_ecc_get_status)), + SPINAND_INFO("GD5F4GQ6UExxG", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x55), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 2, 1), + NAND_ECCREQ(4, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq5xexxg_ecc_get_status)), + SPINAND_INFO("GD5F4GQ6RExxG", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x45), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 2, 1), + NAND_ECCREQ(4, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5, &write_cache_variants, &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, gd5fxgq5xexxg_ecc_get_status)), + SPINAND_INFO("GD5F1GM7UExxG", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x91), + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq4uexxg_ecc_get_status)), + SPINAND_INFO("GD5F1GM7RExxG", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x81), + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq4uexxg_ecc_get_status)), + SPINAND_INFO("GD5F2GM7UExxG", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq4uexxg_ecc_get_status)), + SPINAND_INFO("GD5F2GM7RExxG", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x82), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq4uexxg_ecc_get_status)), + SPINAND_INFO("GD5F4GM8UExxG", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x95), + NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq4uexxg_ecc_get_status)), + SPINAND_INFO("GD5F4GM8RExxG", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x85), + NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq4uexxg_ecc_get_status)), + SPINAND_INFO("GD5F2GQ5xExxH", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x22), + NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(4, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq4uexxg_ecc_get_status)), + SPINAND_INFO("GD5F1GQ5RExxH", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x21), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(4, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq4uexxg_ecc_get_status)), + SPINAND_INFO("GD5F1GQ4RExxH", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xc9), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(4, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq4uexxg_ecc_get_status)), }; static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = { 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/mtd/renesas_rpc_hf.c b/drivers/mtd/renesas_rpc_hf.c index 50a6191d9c2..9390c9e9ab3 100644 --- a/drivers/mtd/renesas_rpc_hf.c +++ b/drivers/mtd/renesas_rpc_hf.c @@ -16,7 +16,6 @@ #include <errno.h> #include <fdt_support.h> #include <flash.h> -#include <mtd.h> #include <wait_bit.h> #include <linux/bitops.h> #include <mtd/cfi_flash.h> diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c index 7c0665faa8e..8fa549280aa 100644 --- a/drivers/net/dc2114x.c +++ b/drivers/net/dc2114x.c @@ -3,6 +3,7 @@ #include <asm/io.h> #include <cpu_func.h> #include <dm.h> +#include <env.h> #include <malloc.h> #include <net.h> #include <netdev.h> 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/mscc_eswitch/jr2_switch.c b/drivers/net/mscc_eswitch/jr2_switch.c index 925888e0765..f0404209116 100644 --- a/drivers/net/mscc_eswitch/jr2_switch.c +++ b/drivers/net/mscc_eswitch/jr2_switch.c @@ -222,7 +222,6 @@ #define CPU_PORT 53 #define IFH_LEN 7 #define JR2_BUF_CELL_SZ 60 -#define ETH_ALEN 6 #define PGID_BROADCAST 510 #define PGID_UNICAST 511 diff --git a/drivers/net/mscc_eswitch/luton_switch.c b/drivers/net/mscc_eswitch/luton_switch.c index 1c584373b8b..be78afc3f79 100644 --- a/drivers/net/mscc_eswitch/luton_switch.c +++ b/drivers/net/mscc_eswitch/luton_switch.c @@ -132,7 +132,6 @@ #define CPU_PORT 26 #define INTERNAL_PORT_MSK 0xFFFFFF #define IFH_LEN 2 -#define ETH_ALEN 6 #define PGID_BROADCAST 28 #define PGID_UNICAST 29 #define PGID_SRC 80 diff --git a/drivers/net/mscc_eswitch/ocelot_switch.c b/drivers/net/mscc_eswitch/ocelot_switch.c index 30bb4b5bad8..b7a8b60587d 100644 --- a/drivers/net/mscc_eswitch/ocelot_switch.c +++ b/drivers/net/mscc_eswitch/ocelot_switch.c @@ -126,7 +126,6 @@ #define CPU_PORT 11 #define INTERNAL_PORT_MSK 0x2FF #define IFH_LEN 4 -#define ETH_ALEN 6 #define PGID_BROADCAST 13 #define PGID_UNICAST 14 #define PGID_SRC 80 diff --git a/drivers/net/mscc_eswitch/serval_switch.c b/drivers/net/mscc_eswitch/serval_switch.c index 8eab41df99a..02f197aa339 100644 --- a/drivers/net/mscc_eswitch/serval_switch.c +++ b/drivers/net/mscc_eswitch/serval_switch.c @@ -111,7 +111,6 @@ #define CPU_PORT 11 #define INTERNAL_PORT_MSK 0xFF #define IFH_LEN 4 -#define ETH_ALEN 6 #define PGID_BROADCAST 13 #define PGID_UNICAST 14 diff --git a/drivers/net/mscc_eswitch/servalt_switch.c b/drivers/net/mscc_eswitch/servalt_switch.c index 61547d7933e..4b073c0781e 100644 --- a/drivers/net/mscc_eswitch/servalt_switch.c +++ b/drivers/net/mscc_eswitch/servalt_switch.c @@ -88,7 +88,6 @@ #define MAC_VID 0 #define CPU_PORT 11 #define IFH_LEN 7 -#define ETH_ALEN 6 #define PGID_BROADCAST 50 #define PGID_UNICAST 51 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/netconsole.c b/drivers/net/netconsole.c index 1943de8ba73..c2ce4a80d12 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -61,8 +61,8 @@ static int is_broadcast(struct in_addr ip) /* update only when the environment has changed */ if (env_changed_id != env_id) { - netmask = env_get_ip("netmask"); - our_ip = env_get_ip("ipaddr"); + netmask = string_to_ip(env_get("netmask")); + our_ip = string_to_ip(env_get("ipaddr")); env_changed_id = env_id; } @@ -81,11 +81,12 @@ static int refresh_settings_from_env(void) /* update only when the environment has changed */ if (env_changed_id != env_id) { - if (env_get("ncip")) { - nc_ip = env_get_ip("ncip"); + char *tmp = env_get("ncip"); + if (tmp) { + nc_ip = string_to_ip(tmp); if (!nc_ip.s_addr) return -1; /* ncip is 0.0.0.0 */ - p = strchr(env_get("ncip"), ':'); + p = strchr(tmp, ':'); if (p != NULL) { nc_out_port = dectoul(p + 1, NULL); nc_in_port = nc_out_port; 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/pfe_eth/pfe_firmware.c b/drivers/net/pfe_eth/pfe_firmware.c index da4f2ca42a5..b821fb17a1d 100644 --- a/drivers/net/pfe_eth/pfe_firmware.c +++ b/drivers/net/pfe_eth/pfe_firmware.c @@ -12,6 +12,7 @@ #include <dm.h> #include <dm/device-internal.h> +#include <env.h> #include <image.h> #include <log.h> #include <malloc.h> 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/phy/phy.c b/drivers/net/phy/phy.c index 716a1d46111..e6fed8c41d7 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -839,8 +839,6 @@ struct phy_device *phy_find_by_mask(struct mii_dev *bus, uint phy_mask) static void phy_connect_dev(struct phy_device *phydev, struct udevice *dev, phy_interface_t interface) { - /* Soft Reset the PHY */ - phy_reset(phydev); if (phydev->dev && phydev->dev != dev) { printf("%s:%d is connected to %s. Reconnecting to %s\n", phydev->bus->name, phydev->addr, diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 409049137cc..8ffd88c722d 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -389,6 +389,16 @@ config PCIE_DW_QCOM Say Y here if you want to enable DW PCIe controller support on Qualcomm SoCs. +config PCI_RCAR_GEN4 + bool "Renesas R-Car Gen4 PCIe driver" + depends on RCAR_GEN4 + select DM_RESET + select DM_GPIO + select PCIE_DW_COMMON + help + Say Y here if you want to enable PCIe controller support on + Renesas R-Car Gen4 SoCs. + config PCIE_ROCKCHIP bool "Enable Rockchip PCIe driver" depends on ARCH_ROCKCHIP diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index ba53f594963..a0420e733ed 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_PCIE_IMX) += pcie_imx.o obj-$(CONFIG_PCI_MVEBU) += pci_mvebu.o obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o obj-$(CONFIG_PCI_RCAR_GEN3) += pci-rcar-gen3.o +obj-$(CONFIG_PCI_RCAR_GEN4) += pci-rcar-gen4.o obj-$(CONFIG_SH7751_PCI) +=pci_sh7751.o obj-$(CONFIG_PCI_TEGRA) += pci_tegra.o obj-$(CONFIG_PCIE_IPROC) += pcie_iproc.o diff --git a/drivers/pci/pci-rcar-gen4.c b/drivers/pci/pci-rcar-gen4.c new file mode 100644 index 00000000000..87cd69f989d --- /dev/null +++ b/drivers/pci/pci-rcar-gen4.c @@ -0,0 +1,565 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * PCIe controller driver for Renesas R-Car Gen4 Series SoCs + * Copyright (C) 2025 Marek Vasut <marek.vasut+renesas@mailbox.org> + * Based on Linux kernel driver + * Copyright (C) 2022-2023 Renesas Electronics Corporation + * + * The r8a779g0 (R-Car V4H) controller requires a specific firmware to be + * provided, to initialize the PHY. Otherwise, the PCIe controller will not + * work. + */ + +#include <asm-generic/gpio.h> +#include <asm/arch/gpio.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <clk.h> +#include <command.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <env.h> +#include <log.h> +#include <reset.h> + +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/iopoll.h> + +#include "pcie_dw_common.h" + +/* Renesas-specific */ +/* PCIe Mode Setting Register 0 */ +#define PCIEMSR0 0x0000 +#define APP_SRIS_MODE BIT(6) +#define DEVICE_TYPE_EP 0 +#define DEVICE_TYPE_RC BIT(4) +#define BIFUR_MOD_SET_ON BIT(0) + +/* PCIe Interrupt Status 0 */ +#define PCIEINTSTS0 0x0084 + +/* PCIe Interrupt Status 0 Enable */ +#define PCIEINTSTS0EN 0x0310 +#define MSI_CTRL_INT BIT(26) +#define SMLH_LINK_UP BIT(7) +#define RDLH_LINK_UP BIT(6) + +/* PCIe DMA Interrupt Status Enable */ +#define PCIEDMAINTSTSEN 0x0314 +#define PCIEDMAINTSTSEN_INIT GENMASK(15, 0) + +/* Port Logic Registers 89 */ +#define PRTLGC89 0x0b70 + +/* Port Logic Registers 90 */ +#define PRTLGC90 0x0b74 + +/* PCIe Reset Control Register 1 */ +#define PCIERSTCTRL1 0x0014 +#define APP_HOLD_PHY_RST BIT(16) +#define APP_LTSSM_ENABLE BIT(0) + +/* PCIe Power Management Control */ +#define PCIEPWRMNGCTRL 0x0070 +#define APP_CLK_REQ_N BIT(11) +#define APP_CLK_PM_EN BIT(10) + +#define RCAR_NUM_SPEED_CHANGE_RETRIES 10 +#define RCAR_MAX_LINK_SPEED 4 + +#define RCAR_GEN4_PCIE_EP_FUNC_DBI_OFFSET 0x1000 +#define RCAR_GEN4_PCIE_EP_FUNC_DBI2_OFFSET 0x800 + +#define RCAR_GEN4_PCIE_FIRMWARE_NAME "rcar_gen4_pcie.bin" +#define RCAR_GEN4_PCIE_FIRMWARE_BASE_ADDR 0xc000 + +#define PCIE_T_PVPERL_MS 100 + +/** + * struct rcar_gen4_pcie - Renesas R-Car Gen4 DW PCIe controller state + * + * @rcar: The common PCIe DW structure + * @pwr_rst: The PWR reset of the PCIe core + * @core_clk: The core clock of the PCIe core + * @ref_clk: The reference clock of the PCIe core and possibly bus + * @pe_rst: PERST GPIO + * @app_base: The base address of application register space + * @dbi2_base: The base address of DBI2 register space + * @phy_base: The base address of PHY register space + * @max_link_speed: Maximum PCIe link speed supported by the setup + * @num_lanes: Number of PCIe lanes used by the setup + * @firmware: PHY firmware + * @firmware_size: PHY firmware size in Bytes + */ +struct rcar_gen4_pcie { + /* Must be first member of the struct */ + struct pcie_dw dw; + struct reset_ctl pwr_rst; + struct clk *core_clk; + struct clk *ref_clk; + struct gpio_desc pe_rst; + void *app_base; + void *dbi2_base; + void *phy_base; + u32 max_link_speed; + u32 num_lanes; + u16 *firmware; + u32 firmware_size; +}; + +/* Common */ +static bool rcar_gen4_pcie_link_up(struct rcar_gen4_pcie *rcar) +{ + u32 val, mask; + + val = readl(rcar->app_base + PCIEINTSTS0); + mask = RDLH_LINK_UP | SMLH_LINK_UP; + + return (val & mask) == mask; +} + +/* + * Manually initiate the speed change. Return 0 if change succeeded; otherwise + * -ETIMEDOUT. + */ +static int rcar_gen4_pcie_speed_change(struct rcar_gen4_pcie *rcar) +{ + u32 val; + int i; + + clrbits_le32(rcar->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL, + PORT_LOGIC_SPEED_CHANGE); + + setbits_le32(rcar->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL, + PORT_LOGIC_SPEED_CHANGE); + + for (i = 0; i < RCAR_NUM_SPEED_CHANGE_RETRIES; i++) { + val = readl(rcar->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); + if (!(val & PORT_LOGIC_SPEED_CHANGE)) + return 0; + mdelay(10); + } + + return -ETIMEDOUT; +} + +/* + * SoC datasheet suggests checking port logic register bits during firmware + * write. If read returns non-zero value, then this function returns -EAGAIN + * indicating that the write needs to be done again. If read returns zero, + * then return 0 to indicate success. + */ +static int rcar_gen4_pcie_reg_test_bit(struct rcar_gen4_pcie *rcar, + u32 offset, u32 mask) +{ + if (readl(rcar->dw.dbi_base + offset) & mask) + return -EAGAIN; + + return 0; +} + +static int rcar_gen4_pcie_download_phy_firmware(struct rcar_gen4_pcie *rcar) +{ + /* The check_addr values are magical numbers in the datasheet */ + static const u32 check_addr[] = { + 0x00101018, + 0x00101118, + 0x00101021, + 0x00101121, + }; + unsigned int i, timeout; + u32 data; + int ret; + + for (i = 0; i < rcar->firmware_size / 2; i++) { + data = rcar->firmware[i]; + timeout = 100; + do { + writel(RCAR_GEN4_PCIE_FIRMWARE_BASE_ADDR + i, rcar->dw.dbi_base + PRTLGC89); + writel(data, rcar->dw.dbi_base + PRTLGC90); + if (!rcar_gen4_pcie_reg_test_bit(rcar, PRTLGC89, BIT(30))) + break; + if (!(--timeout)) + return -ETIMEDOUT; + udelay(100); + } while (1); + } + + setbits_le32(rcar->phy_base + 0x0f8, BIT(17)); + + for (i = 0; i < ARRAY_SIZE(check_addr); i++) { + timeout = 100; + do { + writel(check_addr[i], rcar->dw.dbi_base + PRTLGC89); + ret = rcar_gen4_pcie_reg_test_bit(rcar, PRTLGC89, BIT(30)); + ret |= rcar_gen4_pcie_reg_test_bit(rcar, PRTLGC90, BIT(0)); + if (!ret) + break; + if (!(--timeout)) + return -ETIMEDOUT; + udelay(100); + } while (1); + } + + return ret; +} + +static int rcar_gen4_pcie_ltssm_control(struct rcar_gen4_pcie *rcar, bool enable) +{ + u32 val; + int ret; + + if (!enable) { + clrbits_le32(rcar->app_base + PCIERSTCTRL1, APP_LTSSM_ENABLE); + return 0; + } + + setbits_le32(rcar->dw.dbi_base + PCIE_PORT_FORCE, + PORT_FORCE_DO_DESKEW_FOR_SRIS); + + setbits_le32(rcar->app_base + PCIEMSR0, APP_SRIS_MODE); + + /* + * The R-Car Gen4 datasheet doesn't describe the PHY registers' name. + * But, the initialization procedure describes these offsets. So, + * this driver has magical offset numbers. + */ + clrsetbits_le32(rcar->phy_base + 0x700, BIT(28), 0); + clrsetbits_le32(rcar->phy_base + 0x700, BIT(20), 0); + clrsetbits_le32(rcar->phy_base + 0x700, BIT(12), 0); + clrsetbits_le32(rcar->phy_base + 0x700, BIT(4), 0); + + clrsetbits_le32(rcar->phy_base + 0x148, GENMASK(23, 22), BIT(22)); + clrsetbits_le32(rcar->phy_base + 0x148, GENMASK(18, 16), GENMASK(17, 16)); + clrsetbits_le32(rcar->phy_base + 0x148, GENMASK(7, 6), BIT(6)); + clrsetbits_le32(rcar->phy_base + 0x148, GENMASK(2, 0), GENMASK(11, 0)); + clrsetbits_le32(rcar->phy_base + 0x1d4, GENMASK(16, 15), GENMASK(16, 15)); + clrsetbits_le32(rcar->phy_base + 0x514, BIT(26), BIT(26)); + clrsetbits_le32(rcar->phy_base + 0x0f8, BIT(16), 0); + clrsetbits_le32(rcar->phy_base + 0x0f8, BIT(19), BIT(19)); + + clrbits_le32(rcar->app_base + PCIERSTCTRL1, APP_HOLD_PHY_RST); + + ret = readl_poll_timeout(rcar->phy_base + 0x0f8, val, !(val & BIT(18)), 10000); + if (ret < 0) + return ret; + + ret = rcar_gen4_pcie_download_phy_firmware(rcar); + if (ret) + return ret; + + setbits_le32(rcar->app_base + PCIERSTCTRL1, APP_LTSSM_ENABLE); + + return 0; +} + +/* + * Enable LTSSM of this controller and manually initiate the speed change. + * Always return 0. + */ +static int rcar_gen4_pcie_start_link(struct rcar_gen4_pcie *rcar) +{ + int i, ret; + + ret = rcar_gen4_pcie_ltssm_control(rcar, true); + if (ret) + return ret; + + /* + * Require direct speed change with retrying here if the max_link_speed + * is PCIe Gen2 or higher. + */ + if (rcar->max_link_speed == LINK_SPEED_GEN_1) + return 0; + + for (i = 0; i < RCAR_MAX_LINK_SPEED; i++) { + /* It may not be connected in EP mode yet. So, break the loop */ + if (rcar_gen4_pcie_speed_change(rcar)) + break; + } + + return 0; +} + +static void rcar_gen4_pcie_additional_common_init(struct rcar_gen4_pcie *rcar) +{ + clrsetbits_le32(rcar->dw.dbi_base + PCIE_PORT_LANE_SKEW, + PORT_LANE_SKEW_INSERT_MASK, + (rcar->num_lanes < 4) ? BIT(6) : 0); + + setbits_le32(rcar->app_base + PCIEPWRMNGCTRL, + APP_CLK_REQ_N | APP_CLK_PM_EN); +} + +static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar) +{ + int ret; + + ret = clk_prepare_enable(rcar->core_clk); + if (ret) + return ret; + + ret = reset_assert(&rcar->pwr_rst); + if (ret) + goto err_unprepare; + + setbits_le32(rcar->app_base + PCIEMSR0, + DEVICE_TYPE_RC | + ((rcar->num_lanes < 4) ? BIFUR_MOD_SET_ON : 0)); + + ret = reset_deassert(&rcar->pwr_rst); + if (ret) + goto err_unprepare; + + rcar_gen4_pcie_additional_common_init(rcar); + + return 0; + +err_unprepare: + clk_disable_unprepare(rcar->core_clk); + + return ret; +} + +/* Host mode */ +static int rcar_gen4_pcie_host_init(struct udevice *dev) +{ + struct rcar_gen4_pcie *rcar = dev_get_priv(dev); + int ret; + + dm_gpio_set_value(&rcar->pe_rst, 1); + + ret = rcar_gen4_pcie_common_init(rcar); + if (ret) + return ret; + + /* + * According to the section 3.5.7.2 "RC Mode" in DWC PCIe Dual Mode + * Rev.5.20a and 3.5.6.1 "RC mode" in DWC PCIe RC databook v5.20a, we + * should disable two BARs to avoid unnecessary memory assignment + * during device enumeration. + */ + writel(0x0, rcar->dbi2_base + PCI_BASE_ADDRESS_0); + writel(0x0, rcar->dbi2_base + PCI_BASE_ADDRESS_1); + + /* Disable MSI interrupt signal */ + clrbits_le32(rcar->app_base + PCIEINTSTS0EN, MSI_CTRL_INT); + + mdelay(PCIE_T_PVPERL_MS); /* pe_rst requires 100msec delay */ + + dm_gpio_set_value(&rcar->pe_rst, 0); + + return 0; +} + +static int rcar_gen4_pcie_load_firmware(struct rcar_gen4_pcie *rcar) +{ + ulong addr, size; + int ret; + + /* + * Run user specified firmware loading script, which loads the + * firmware from whichever location the user decides it should + * load the firmware from, by whatever means the user decides. + */ + ret = run_command_list("run renesas_rcar_gen4_load_firmware", -1, 0); + if (ret) { + printf("Firmware loading script 'renesas_rcar_gen4_load_firmware' not defined or failed.\n"); + goto fail; + } + + /* Find out where the firmware got loaded and how long it is. */ + addr = env_get_hex("renesas_rcar_gen4_load_firmware_addr", 0); + size = env_get_hex("renesas_rcar_gen4_load_firmware_size", 0); + + /* + * Clear the variables set by the firmware loading script, as + * their content would become stale once this function exits. + */ + env_set("renesas_rcar_gen4_load_firmware_addr", NULL); + env_set("renesas_rcar_gen4_load_firmware_size", NULL); + + if (!addr || !size) { + printf("Firmware address (%lx) or size (%lx) are invalid.\n", addr, size); + goto fail; + } + + /* Create local copy of the loaded firmware. */ + rcar->firmware = (u16 *)memdup((void *)addr, size); + if (!rcar->firmware) + return -ENOMEM; + + rcar->firmware_size = size; + + return 0; + +fail: + printf("Define 'renesas_rcar_gen4_load_firmware' script which loads the R-Car\n" + "Gen4 PCIe controller firmware from storage into memory and sets these\n" + "two environment variables:\n" + " renesas_rcar_gen4_load_firmware_addr ... address of firmware in memory\n" + " renesas_rcar_gen4_load_firmware_size ... length of firmware in bytes\n" + "\n" + "Example:\n" + " => env set renesas_rcar_gen4_load_firmware 'env set renesas_rcar_gen4_load_firmware_addr 0x54000000 && load mmc 0:1 ${renesas_rcar_gen4_load_firmware_addr} lib/firmware/rcar_gen4_pcie.bin && env set renesas_rcar_gen4_load_firmware_size ${filesize}'\n" + ); + return -EINVAL; +} + +/** + * rcar_gen4_pcie_probe() - Probe the PCIe bus for active link + * + * @dev: A pointer to the device being operated on + * + * Probe for an active link on the PCIe bus and configure the controller + * to enable this port. + * + * Return: 0 on success, else -ENODEV + */ +static int rcar_gen4_pcie_probe(struct udevice *dev) +{ + struct rcar_gen4_pcie *rcar = dev_get_priv(dev); + struct udevice *ctlr = pci_get_controller(dev); + struct pci_controller *hose = dev_get_uclass_priv(ctlr); + int ret; + + ret = rcar_gen4_pcie_load_firmware(rcar); + if (ret) + return ret; + + rcar->dw.first_busno = dev_seq(dev); + rcar->dw.dev = dev; + + ret = reset_get_by_name(dev, "pwr", &rcar->pwr_rst); + if (ret) + return ret; + + rcar->core_clk = devm_clk_get(dev, "core"); + if (IS_ERR(rcar->core_clk)) + return PTR_ERR(rcar->core_clk); + + rcar->ref_clk = devm_clk_get(dev, "ref"); + if (IS_ERR(rcar->ref_clk)) + return PTR_ERR(rcar->ref_clk); + + ret = clk_prepare_enable(rcar->ref_clk); + if (ret) + return ret; + + ret = gpio_request_by_name(dev, "reset-gpios", 0, &rcar->pe_rst, + GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); + if (ret) + return ret; + + ret = rcar_gen4_pcie_host_init(dev); + if (ret) + return ret; + + pcie_dw_setup_host(&rcar->dw); + + dw_pcie_dbi_write_enable(&rcar->dw, true); + + dw_pcie_link_set_max_link_width(&rcar->dw, rcar->num_lanes); + + ret = rcar_gen4_pcie_start_link(rcar); + if (ret) + return ret; + + dw_pcie_dbi_write_enable(&rcar->dw, false); + + if (!rcar_gen4_pcie_link_up(rcar)) { + printf("PCIE-%d: Link down\n", dev_seq(dev)); + return -ENODEV; + } + + printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n", dev_seq(dev), + pcie_dw_get_link_speed(&rcar->dw), + pcie_dw_get_link_width(&rcar->dw), + hose->first_busno); + + pcie_dw_prog_outbound_atu_unroll(&rcar->dw, PCIE_ATU_REGION_INDEX0, + PCIE_ATU_TYPE_MEM, + rcar->dw.mem.phys_start, + rcar->dw.mem.bus_start, rcar->dw.mem.size); + + return 0; +} + +/** + * rcar_gen4_pcie_of_to_plat() - Translate from DT to device state + * + * @dev: A pointer to the device being operated on + * + * Translate relevant data from the device tree pertaining to device @dev into + * state that the driver will later make use of. This state is stored in the + * device's private data structure. + * + * Return: 0 on success, else -EINVAL + */ +static int rcar_gen4_pcie_of_to_plat(struct udevice *dev) +{ + struct rcar_gen4_pcie *rcar = dev_get_priv(dev); + + /* Get the controller base address */ + rcar->dw.dbi_base = (void *)dev_read_addr_name(dev, "dbi"); + if ((fdt_addr_t)rcar->dw.dbi_base == FDT_ADDR_T_NONE) + return -EINVAL; + + /* Get the config space base address and size */ + rcar->dw.cfg_base = (void *)dev_read_addr_size_name(dev, "config", + &rcar->dw.cfg_size); + if ((fdt_addr_t)rcar->dw.cfg_base == FDT_ADDR_T_NONE) + return -EINVAL; + + /* Get the iATU base address and size */ + rcar->dw.atu_base = (void *)dev_read_addr_name(dev, "atu"); + if ((fdt_addr_t)rcar->dw.atu_base == FDT_ADDR_T_NONE) + return -EINVAL; + + /* Get the PHY base address and size */ + rcar->phy_base = (void *)dev_read_addr_name(dev, "phy"); + if ((fdt_addr_t)rcar->phy_base == FDT_ADDR_T_NONE) + return -EINVAL; + + /* Get the app base address and size */ + rcar->app_base = (void *)dev_read_addr_name(dev, "app"); + if ((fdt_addr_t)rcar->app_base == FDT_ADDR_T_NONE) + return -EINVAL; + + /* Get the dbi2 base address and size */ + rcar->dbi2_base = (void *)dev_read_addr_name(dev, "dbi2"); + if ((fdt_addr_t)rcar->dbi2_base == FDT_ADDR_T_NONE) + return -EINVAL; + + rcar->max_link_speed = + clamp(dev_read_u32_default(dev, "max-link-speed", + LINK_SPEED_GEN_4), + LINK_SPEED_GEN_1, RCAR_MAX_LINK_SPEED); + + rcar->num_lanes = dev_read_u32_default(dev, "num-lanes", 4); + + return 0; +} + +static const struct dm_pci_ops rcar_gen4_pcie_ops = { + .read_config = pcie_dw_read_config, + .write_config = pcie_dw_write_config, +}; + +static const struct udevice_id rcar_gen4_pcie_ids[] = { + { .compatible = "renesas,rcar-gen4-pcie" }, + { } +}; + +U_BOOT_DRIVER(rcar_gen4_pcie) = { + .name = "rcar_gen4_pcie", + .id = UCLASS_PCI, + .of_match = rcar_gen4_pcie_ids, + .ops = &rcar_gen4_pcie_ops, + .of_to_plat = rcar_gen4_pcie_of_to_plat, + .probe = rcar_gen4_pcie_probe, + .priv_auto = sizeof(struct rcar_gen4_pcie), +}; diff --git a/drivers/pci/pcie_dw_common.c b/drivers/pci/pcie_dw_common.c index 78961271a8e..c4cad019373 100644 --- a/drivers/pci/pcie_dw_common.c +++ b/drivers/pci/pcie_dw_common.c @@ -13,6 +13,7 @@ #include <pci.h> #include <dm/device_compat.h> #include <asm/io.h> +#include <linux/bitfield.h> #include <linux/delay.h> #include "pcie_dw_common.h" @@ -28,6 +29,50 @@ int pcie_dw_get_link_width(struct pcie_dw *pci) PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF; } +void dw_pcie_link_set_max_link_width(struct pcie_dw *pci, u32 num_lanes) +{ + u32 lnkcap, lwsc, plc; + u8 cap; + + if (!num_lanes) + return; + + /* Set the number of lanes */ + plc = readl(pci->dbi_base + PCIE_PORT_LINK_CONTROL); + plc &= ~PORT_LINK_FAST_LINK_MODE; + plc &= ~PORT_LINK_MODE_MASK; + + /* Set link width speed control register */ + lwsc = readl(pci->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); + lwsc &= ~PORT_LOGIC_LINK_WIDTH_MASK; + lwsc |= PORT_LOGIC_LINK_WIDTH_1_LANES; + switch (num_lanes) { + case 1: + plc |= PORT_LINK_MODE_1_LANES; + break; + case 2: + plc |= PORT_LINK_MODE_2_LANES; + break; + case 4: + plc |= PORT_LINK_MODE_4_LANES; + break; + case 8: + plc |= PORT_LINK_MODE_8_LANES; + break; + default: + dev_err(pci->dev, "num-lanes %u: invalid value\n", num_lanes); + return; + } + writel(plc, pci->dbi_base + PCIE_PORT_LINK_CONTROL); + writel(lwsc, pci->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); + + cap = pcie_dw_find_capability(pci, PCI_CAP_ID_EXP); + lnkcap = readl(pci->dbi_base + cap + PCI_EXP_LNKCAP); + lnkcap &= ~PCI_EXP_LNKCAP_MLW; + lnkcap |= FIELD_PREP(PCI_EXP_LNKCAP_MLW, num_lanes); + writel(lnkcap, pci->dbi_base + cap + PCI_EXP_LNKCAP); +} + static void dw_pcie_writel_ob_unroll(struct pcie_dw *pci, u32 index, u32 reg, u32 val) { diff --git a/drivers/pci/pcie_dw_common.h b/drivers/pci/pcie_dw_common.h index 8cb99a12ea1..5fa50f3dc3a 100644 --- a/drivers/pci/pcie_dw_common.h +++ b/drivers/pci/pcie_dw_common.h @@ -66,8 +66,12 @@ #define LINK_SPEED_GEN_1 0x1 #define LINK_SPEED_GEN_2 0x2 #define LINK_SPEED_GEN_3 0x3 +#define LINK_SPEED_GEN_4 0x4 /* Synopsys-specific PCIe configuration registers */ +#define PCIE_PORT_FORCE 0x708 +#define PORT_FORCE_DO_DESKEW_FOR_SRIS BIT(23) + #define PCIE_PORT_LINK_CONTROL 0x710 #define PORT_LINK_DLL_LINK_EN BIT(5) #define PORT_LINK_FAST_LINK_MODE BIT(7) @@ -78,6 +82,9 @@ #define PORT_LINK_MODE_4_LANES PORT_LINK_MODE(0x7) #define PORT_LINK_MODE_8_LANES PORT_LINK_MODE(0xf) +#define PCIE_PORT_LANE_SKEW 0x714 +#define PORT_LANE_SKEW_INSERT_MASK GENMASK(23, 0) + #define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C #define PORT_LOGIC_N_FTS_MASK GENMASK(7, 0) #define PORT_LOGIC_SPEED_CHANGE BIT(17) @@ -130,6 +137,8 @@ int pcie_dw_get_link_speed(struct pcie_dw *pci); int pcie_dw_get_link_width(struct pcie_dw *pci); +void dw_pcie_link_set_max_link_width(struct pcie_dw *pci, u32 num_lanes); + int pcie_dw_prog_outbound_atu_unroll(struct pcie_dw *pci, int index, int type, u64 cpu_addr, u64 pci_addr, u32 size); diff --git a/drivers/pci/pcie_dw_meson.c b/drivers/pci/pcie_dw_meson.c index bb78e7874b1..483b07ce078 100644 --- a/drivers/pci/pcie_dw_meson.c +++ b/drivers/pci/pcie_dw_meson.c @@ -115,13 +115,9 @@ static void meson_pcie_configure(struct meson_pcie *priv) val &= ~PORT_LINK_FAST_LINK_MODE; val |= PORT_LINK_DLL_LINK_EN; val &= ~PORT_LINK_MODE_MASK; - val |= PORT_LINK_MODE_1_LANES; writel(val, priv->dw.dbi_base + PCIE_PORT_LINK_CONTROL); - val = readl(priv->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); - val &= ~PORT_LOGIC_LINK_WIDTH_MASK; - val |= PORT_LOGIC_LINK_WIDTH_1_LANES; - writel(val, priv->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); + dw_pcie_link_set_max_link_width(&priv->dw, 1); dw_pcie_dbi_write_enable(&priv->dw, false); } diff --git a/drivers/pci/pcie_dw_qcom.c b/drivers/pci/pcie_dw_qcom.c index 39b4cd4efe2..978754e8472 100644 --- a/drivers/pci/pcie_dw_qcom.c +++ b/drivers/pci/pcie_dw_qcom.c @@ -213,17 +213,6 @@ static void qcom_pcie_clear_hpc(struct qcom_pcie *priv) dw_pcie_dbi_write_enable(&priv->dw, false); } -static void qcom_pcie_set_lanes(struct qcom_pcie *priv, unsigned int lanes) -{ - u8 offset = pcie_dw_find_capability(&priv->dw, PCI_CAP_ID_EXP); - u32 val; - - val = readl(priv->dw.dbi_base + offset + PCI_EXP_LNKCAP); - val &= ~PCI_EXP_LNKCAP_MLW; - val |= FIELD_PREP(PCI_EXP_LNKCAP_MLW, lanes); - writel(val, priv->dw.dbi_base + offset + PCI_EXP_LNKCAP); -} - static int qcom_pcie_config_sid_1_9_0(struct qcom_pcie *priv) { /* iommu map structure */ @@ -299,15 +288,9 @@ static void qcom_pcie_configure(struct qcom_pcie *priv) val &= ~PORT_LINK_FAST_LINK_MODE; val |= PORT_LINK_DLL_LINK_EN; val &= ~PORT_LINK_MODE_MASK; - val |= PORT_LINK_MODE_2_LANES; writel(val, priv->dw.dbi_base + PCIE_PORT_LINK_CONTROL); - val = readl(priv->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); - val &= ~PORT_LOGIC_LINK_WIDTH_MASK; - val |= PORT_LOGIC_LINK_WIDTH_2_LANES; - writel(val, priv->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); - - qcom_pcie_set_lanes(priv, 2); + dw_pcie_link_set_max_link_width(&priv->dw, 2); dw_pcie_dbi_write_enable(&priv->dw, false); } diff --git a/drivers/pci/pcie_dw_rockchip.c b/drivers/pci/pcie_dw_rockchip.c index ac7faa4cc19..208aa30463a 100644 --- a/drivers/pci/pcie_dw_rockchip.c +++ b/drivers/pci/pcie_dw_rockchip.c @@ -158,8 +158,6 @@ static inline void rk_pcie_writel_apb(struct rk_pcie *rk_pcie, u32 reg, */ static void rk_pcie_configure(struct rk_pcie *pci) { - u32 val; - dw_pcie_dbi_write_enable(&pci->dw, true); /* Disable BAR 0 and BAR 1 */ @@ -175,43 +173,8 @@ static void rk_pcie_configure(struct rk_pcie *pci) TARGET_LINK_SPEED_MASK, pci->gen); /* Set the number of lanes */ - val = readl(pci->dw.dbi_base + PCIE_PORT_LINK_CONTROL); - val &= ~PORT_LINK_FAST_LINK_MODE; - val |= PORT_LINK_DLL_LINK_EN; - val &= ~PORT_LINK_MODE_MASK; - switch (pci->num_lanes) { - case 1: - val |= PORT_LINK_MODE_1_LANES; - break; - case 2: - val |= PORT_LINK_MODE_2_LANES; - break; - case 4: - val |= PORT_LINK_MODE_4_LANES; - break; - default: - dev_err(pci->dw.dev, "num-lanes %u: invalid value\n", pci->num_lanes); - goto out; - } - writel(val, pci->dw.dbi_base + PCIE_PORT_LINK_CONTROL); - - /* Set link width speed control register */ - val = readl(pci->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); - val &= ~PORT_LOGIC_LINK_WIDTH_MASK; - switch (pci->num_lanes) { - case 1: - val |= PORT_LOGIC_LINK_WIDTH_1_LANES; - break; - case 2: - val |= PORT_LOGIC_LINK_WIDTH_2_LANES; - break; - case 4: - val |= PORT_LOGIC_LINK_WIDTH_4_LANES; - break; - } - writel(val, pci->dw.dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); + dw_pcie_link_set_max_link_width(&pci->dw, pci->num_lanes); -out: dw_pcie_dbi_write_enable(&pci->dw, false); } diff --git a/drivers/pci_endpoint/Kconfig b/drivers/pci_endpoint/Kconfig index 19cfa0aafb5..9900481daa6 100644 --- a/drivers/pci_endpoint/Kconfig +++ b/drivers/pci_endpoint/Kconfig @@ -22,6 +22,12 @@ config PCIE_CADENCE_EP endpoint mode. This PCIe controller may be embedded into many different vendors SoCs. +config PCIE_CDNS_TI_EP + bool "TI K3 PCIe EP support" + help + Say Y here to enable support for the Canence PCIe Controller + in Endpoint Mode on TI's K3 Socs. + config PCI_SANDBOX_EP bool "Sandbox PCIe endpoint controller" depends on PCI_ENDPOINT diff --git a/drivers/pci_endpoint/Makefile b/drivers/pci_endpoint/Makefile index 3cd987259d3..62a865c4463 100644 --- a/drivers/pci_endpoint/Makefile +++ b/drivers/pci_endpoint/Makefile @@ -6,3 +6,4 @@ obj-y += pci_ep-uclass.o obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o obj-$(CONFIG_PCI_SANDBOX_EP) += sandbox-pci_ep.o +obj-$(CONFIG_PCIE_CDNS_TI_EP) += pcie_cdns_ti_ep.o diff --git a/drivers/pci_endpoint/pcie_cdns_ti_ep.c b/drivers/pci_endpoint/pcie_cdns_ti_ep.c new file mode 100644 index 00000000000..59c17d0f1e4 --- /dev/null +++ b/drivers/pci_endpoint/pcie_cdns_ti_ep.c @@ -0,0 +1,395 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Copyright (C) 2025 Texas Instruments Incorporated - https://www.ti.com + * + * PCIe Endpoint controller driver for TI's K3 SoCs with Cadence PCIe controller + * + * Ported from the Linux driver - drivers/pci/controller/cadence/pci-j721e.c + * + * Author: Hrushikesh Salunke <h-salunke@ti.com> + * + */ + +#include <clk.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <generic-phy.h> +#include <linux/log2.h> +#include <linux/sizes.h> +#include <power-domain.h> +#include <regmap.h> +#include <syscon.h> +#include <pcie-cadence.h> +#include <pci_ep.h> + +#define PCIE_USER_CMD_STATUS_REG_OFFSET 0x4 +#define LINK_TRAINING_ENABLE BIT(0) + +#define PCIE_MODE_SEL_MASK BIT(7) +#define PCIE_GEN_SEL_MASK GENMASK(1, 0) +#define PCIE_LINK_WIDTH_MASK GENMASK(9, 8) + +struct pcie_cdns_ti_ep_data { + unsigned int quirk_retrain_flag:1; + unsigned int quirk_detect_quiet_flag:1; + unsigned int quirk_disable_flr:1; + unsigned int byte_access_allowed:1; + unsigned int max_lanes; +}; + +struct pcie_cdns_ti_ep { + struct udevice *dev; + void __iomem *intd_cfg_base; + void __iomem *user_cfg_base; + void __iomem *reg_base; + void __iomem *mem_base; + fdt_size_t cfg_size; + struct regmap *syscon_base; + u32 max_link_speed; + u32 num_lanes; + u32 pcie_ctrl_offset; + unsigned int quirk_retrain_flag:1; + unsigned int quirk_detect_quiet_flag:1; + unsigned int quirk_disable_flr:1; + unsigned int byte_access_allowed:1; +}; + +static inline u32 pcie_cdns_ti_ep_user_readl(struct pcie_cdns_ti_ep *pcie, u32 offset) +{ + return readl(pcie->user_cfg_base + offset); +} + +static inline void pcie_cdns_ti_ep_user_writel(struct pcie_cdns_ti_ep *pcie, u32 offset, + u32 val) +{ + writel(val, pcie->user_cfg_base + offset); +} + +static void pcie_cdns_ti_start_link(struct pcie_cdns_ti_ep *pcie) +{ + u32 reg; + + reg = pcie_cdns_ti_ep_user_readl(pcie, PCIE_USER_CMD_STATUS_REG_OFFSET); + reg |= LINK_TRAINING_ENABLE; + pcie_cdns_ti_ep_user_writel(pcie, PCIE_USER_CMD_STATUS_REG_OFFSET, reg); +} + +static int pcie_cdns_reset(struct udevice *dev, struct power_domain *pci_pwrdmn) +{ + int ret; + + ret = power_domain_off(pci_pwrdmn); + if (ret) { + dev_err(dev, "failed to power off\n"); + return ret; + } + + ret = power_domain_on(pci_pwrdmn); + if (ret) { + dev_err(dev, "failed to power on: %d\n", ret); + return ret; + } + + return 0; +} + +static int pcie_cdns_config_serdes(struct udevice *dev) +{ + if (CONFIG_IS_ENABLED(PHY_CADENCE_TORRENT)) { + struct phy serdes; + int ret = 7; + + ret = generic_phy_get_by_name(dev, "pcie-phy", &serdes); + if (ret != 0 && ret != -EBUSY) { + dev_err(dev, "unable to get serdes\n"); + return ret; + } + generic_phy_reset(&serdes); + generic_phy_init(&serdes); + generic_phy_power_on(&serdes); + } else { + dev_info(dev, "Proceeding with the assumption that the SERDES is already configured\n"); + } + return 0; +} + +static int pcie_cdns_ti_ctrl_init(struct pcie_cdns_ti_ep *pcie) +{ + struct regmap *syscon = pcie->syscon_base; + u32 val = 0; + + /* Set mode of operation */ + regmap_update_bits(syscon, pcie->pcie_ctrl_offset, PCIE_MODE_SEL_MASK, + val); + + /* Set link speed */ + regmap_update_bits(syscon, pcie->pcie_ctrl_offset, PCIE_GEN_SEL_MASK, + pcie->max_link_speed - 1); + + /* Set link width */ + regmap_update_bits(syscon, pcie->pcie_ctrl_offset, PCIE_LINK_WIDTH_MASK, + (pcie->num_lanes - 1) << 8); + return 0; +} + +static int pcie_cdns_ti_write_header(struct udevice *dev, uint fn, + struct pci_ep_header *hdr) +{ + struct pcie_cdns_ti_ep *pcie_ep = dev_get_priv(dev); + struct cdns_pcie pcie; + + pcie.reg_base = pcie_ep->reg_base; + + cdns_pcie_ep_fn_writew(&pcie, fn, PCI_DEVICE_ID, hdr->deviceid); + cdns_pcie_ep_fn_writeb(&pcie, fn, PCI_REVISION_ID, hdr->revid); + cdns_pcie_ep_fn_writeb(&pcie, fn, PCI_CLASS_PROG, + hdr->progif_code); + cdns_pcie_ep_fn_writew(&pcie, fn, PCI_CLASS_DEVICE, + hdr->subclass_code | + hdr->baseclass_code << 8); + cdns_pcie_ep_fn_writeb(&pcie, fn, PCI_CACHE_LINE_SIZE, + hdr->cache_line_size); + cdns_pcie_ep_fn_writew(&pcie, fn, PCI_SUBSYSTEM_ID, + hdr->subsys_id); + cdns_pcie_ep_fn_writeb(&pcie, fn, PCI_INTERRUPT_PIN, + hdr->interrupt_pin); + + /* + * Vendor ID can only be modified from function 0, all other functions + * use the same vendor ID as function 0. + */ + if (fn == 0) { + /* Update the vendor IDs. */ + u32 id = CDNS_PCIE_LM_ID_VENDOR(hdr->vendorid) | + CDNS_PCIE_LM_ID_SUBSYS(hdr->subsys_vendor_id); + + cdns_pcie_writel(&pcie, CDNS_PCIE_LM_ID, id); + } + + return 0; +} + +static int pcie_cdns_ti_set_bar(struct udevice *dev, uint fn, + struct pci_bar *ep_bar) +{ + struct pcie_cdns_ti_ep *pcie_ep = dev_get_priv(dev); + struct cdns_pcie pcie; + dma_addr_t bar_phys = ep_bar->phys_addr; + enum pci_barno bar = ep_bar->barno; + int flags = ep_bar->flags; + u32 addr0, addr1, reg, cfg, b, aperture, ctrl; + u64 sz; + + pcie.reg_base = pcie_ep->reg_base; + + /* BAR size is 2^(aperture + 7) */ + sz = max_t(size_t, ep_bar->size, CDNS_PCIE_EP_MIN_APERTURE); + /* + * roundup_pow_of_two() returns an unsigned long, which is not suited + * for 64bit values. + */ + sz = 1ULL << fls64(sz - 1); + aperture = ilog2(sz) - 7; /* 128B -> 0, 256B -> 1, 512B -> 2, ... */ + + if ((flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) { + ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS; + } else { + bool is_prefetch = !!(flags & PCI_BASE_ADDRESS_MEM_PREFETCH); + bool is_64bits = (sz > SZ_2G) | + !!(ep_bar->flags & PCI_BASE_ADDRESS_MEM_TYPE_64); + + if (is_64bits && (bar & 1)) + return -EINVAL; + + if (is_64bits && !(flags & PCI_BASE_ADDRESS_MEM_TYPE_64)) + ep_bar->flags |= PCI_BASE_ADDRESS_MEM_TYPE_64; + + if (is_64bits && is_prefetch) + ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS; + else if (is_prefetch) + ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS; + else if (is_64bits) + ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS; + else + ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS; + } + + addr0 = lower_32_bits(bar_phys); + addr1 = upper_32_bits(bar_phys); + cdns_pcie_writel(&pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), + addr0); + cdns_pcie_writel(&pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), + addr1); + + /* + * Cadence PCIe controller provides a register interface to configure + * BAR of an Endpoint function. Per function there are two BAR configuration + * registers, out of which first is used to configure BAR_0 to BAR_4 and + * second is used to configure the remaining BARs. + */ + if (bar < BAR_4) { + reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn); + b = bar; + } else { + reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn); + b = bar - BAR_4; + } + + cfg = cdns_pcie_readl(&pcie, reg); + + cfg &= ~(CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) | + CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b)); + cfg |= (CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE(b, aperture) | + CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl)); + cdns_pcie_writel(&pcie, reg, cfg); + + cfg = cdns_pcie_readl(&pcie, reg); + + return 0; +} + +static int pcie_cdns_ti_start(struct udevice *dev) +{ + struct pcie_cdns_ti_ep *pcie = dev_get_priv(dev); + + pcie_cdns_ti_start_link(pcie); + + return 0; +} + +static int pcie_cdns_ti_ep_probe(struct udevice *dev) +{ + struct pcie_cdns_ti_ep *pcie = dev_get_priv(dev); + struct pcie_cdns_ti_ep_data *data; + struct power_domain pci_pwrdmn; + struct clk *clk; + int ret; + + pcie->dev = dev; + data = (struct pcie_cdns_ti_ep_data *)dev_get_driver_data(dev); + if (!data) + return -EINVAL; + + pcie->quirk_retrain_flag = data->quirk_retrain_flag; + pcie->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag; + pcie->quirk_disable_flr = data->quirk_disable_flr; + + if (pcie->num_lanes > data->max_lanes) { + dev_warn(dev, "cannot support %d lanes, defaulting to %d\n", + pcie->num_lanes, data->max_lanes); + pcie->num_lanes = data->max_lanes; + } + + ret = power_domain_get_by_index(dev, &pci_pwrdmn, 0); + if (ret) { + dev_err(dev, "failed to get power domain: %d\n", ret); + return ret; + } + + /* + * Reset the PCIe controller so that newly configured BAR + * values are reflected. + */ + ret = pcie_cdns_reset(dev, &pci_pwrdmn); + if (ret) { + dev_err(dev, "failed to reset controller: %d\n", ret); + return ret; + } + + clk = devm_clk_get(dev, "fck"); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + dev_err(dev, "failed to get functional clock\n"); + return ret; + } + + ret = pcie_cdns_config_serdes(dev); + if (ret) { + dev_err(dev, "failed to configure serdes: %d\n", ret); + return ret; + } + + ret = pcie_cdns_ti_ctrl_init(pcie); + if (ret) { + dev_err(dev, "failed to initialize controller: %d\n", ret); + return ret; + } + + return 0; +} + +static int pcie_cdns_ti_ep_of_to_plat(struct udevice *dev) +{ + struct pcie_cdns_ti_ep *pcie = dev_get_priv(dev); + struct regmap *syscon; + u32 offset; + int ret; + + pcie->intd_cfg_base = dev_remap_addr_name(dev, "intd_cfg"); + if (!pcie->intd_cfg_base) + return -EINVAL; + + pcie->user_cfg_base = dev_remap_addr_name(dev, "user_cfg"); + if (!pcie->user_cfg_base) + return -EINVAL; + + pcie->reg_base = dev_remap_addr_name(dev, "reg"); + if (!pcie->reg_base) + return -EINVAL; + + pcie->mem_base = dev_remap_addr_name(dev, "mem"); + if (!pcie->mem_base) + return -EINVAL; + + ret = dev_read_u32(dev, "num-lanes", &pcie->num_lanes); + if (ret) + return ret; + + ret = dev_read_u32(dev, "max-link-speed", &pcie->max_link_speed); + if (ret) + return ret; + + syscon = syscon_regmap_lookup_by_phandle(dev, "ti,syscon-pcie-ctrl"); + if (IS_ERR(syscon)) { + if (PTR_ERR(syscon) == -ENODEV) + return 0; + return PTR_ERR(syscon); + } + + ret = dev_read_u32_index(dev, "ti,syscon-pcie-ctrl", 1, &offset); + if (ret) + return ret; + + pcie->syscon_base = syscon; + pcie->pcie_ctrl_offset = offset; + + return 0; +} + +static const struct pci_ep_ops pcie_cdns_ti_ep_ops = { + .write_header = pcie_cdns_ti_write_header, + .set_bar = pcie_cdns_ti_set_bar, + .start = pcie_cdns_ti_start, +}; + +static const struct pcie_cdns_ti_ep_data am64_pcie_ep_data = { + .max_lanes = 1, +}; + +static const struct udevice_id pcie_cdns_ti_ep_ids[] = { + { + .compatible = "ti,am64-pcie-ep", + .data = (ulong)&am64_pcie_ep_data, + }, + {}, +}; + +U_BOOT_DRIVER(pcie_cdns_ti_ep) = { + .name = "pcie_cdns_ti_ep", + .id = UCLASS_PCI_EP, + .of_match = pcie_cdns_ti_ep_ids, + .ops = &pcie_cdns_ti_ep_ops, + .of_to_plat = pcie_cdns_ti_ep_of_to_plat, + .probe = pcie_cdns_ti_ep_probe, + .priv_auto = sizeof(struct pcie_cdns_ti_ep), +}; diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index d4e8ece4935..1f566d082f9 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -240,6 +240,7 @@ struct cdns_torrent_inst { struct cdns_torrent_phy { void __iomem *sd_base; /* SD0801 register base */ + u32 protocol_bitmask; size_t size; struct reset_control *phy_rst; struct udevice *dev; @@ -432,124 +433,155 @@ static int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_ph struct cdns_reg_pairs *reg_pairs; enum cdns_torrent_ssc_mode ssc; struct regmap *regmap; - u32 num_regs; + u32 num_regs, num_protocols, protocol; + + num_protocols = hweight32(cdns_phy->protocol_bitmask); - /* Maximum 2 links (subnodes) are supported */ - if (cdns_phy->nsubnodes != 2) + /* Maximum 2 protocols are supported */ + if (num_protocols > 2) { + dev_err(cdns_phy->dev, "at most 2 protocols are supported\n"); return -EINVAL; + } - phy_t1 = cdns_phy->phys[0].phy_type; - phy_t2 = cdns_phy->phys[1].phy_type; + if (cdns_phy->nsubnodes == 2) { + phy_t1 = cdns_phy->phys[0].phy_type; + phy_t2 = cdns_phy->phys[1].phy_type; + } else { + if (num_protocols != 2) { + dev_err(cdns_phy->dev, "incorrect representation of link\n"); + return -EINVAL; + } + phy_t1 = __ffs(cdns_phy->protocol_bitmask); + phy_t2 = __fls(cdns_phy->protocol_bitmask); + } - /* - * First configure the PHY for first link with phy_t1. Geth the array - * values are [phy_t1][phy_t2][ssc]. + /** + * Configure all links with the protocol phy_t1 first followed by + * configuring all links with the protocol phy_t2. + * + * When phy_t1 = phy_t2, it is a single protocol and configuration + * is performed with a single iteration of the protocol and multiple + * iterations over the sub-nodes (links). + * + * When phy_t1 != phy_t2, there are two protocols and configuration + * is performed by iterating over all sub-nodes matching the first + * protocol and configuring them first, followed by iterating over + * all sub-nodes matching the second protocol and configuring them + * next. */ - for (node = 0; node < cdns_phy->nsubnodes; node++) { - if (node == 1) { - /* - * If fist link with phy_t1 is configured, then - * configure the PHY for second link with phy_t2. - * Get the array values as [phy_t2][phy_t1][ssc] - */ + + for (protocol = 0; protocol < num_protocols; protocol++) { + /** + * For the case where num_protocols is 1, + * phy_t1 = phy_t2 and the swap is unnecessary. + * + * Swapping phy_t1 and phy_t2 is only required when the + * number of protocols is 2 and there are 2 or more links. + */ + if (protocol == 1) { tmp_phy_type = phy_t1; phy_t1 = phy_t2; phy_t2 = tmp_phy_type; } - mlane = cdns_phy->phys[node].mlane; - ssc = cdns_phy->phys[node].ssc_mode; - num_lanes = cdns_phy->phys[node].num_lanes; + for (node = 0; node < cdns_phy->nsubnodes; node++) { + if (cdns_phy->phys[node].phy_type != phy_t1) + continue; - /** - * PHY configuration specific registers: - * link_cmn_vals depend on combination of PHY types being - * configured and are common for both PHY types, so array - * values should be same for [phy_t1][phy_t2][ssc] and - * [phy_t2][phy_t1][ssc]. - * xcvr_diag_vals also depend on combination of PHY types - * being configured, but these can be different for particular - * PHY type and are per lane. - */ - link_cmn_vals = init_data->link_cmn_vals[phy_t1][phy_t2][ssc]; - if (link_cmn_vals) { - reg_pairs = link_cmn_vals->reg_pairs; - num_regs = link_cmn_vals->num_regs; - regmap = cdns_phy->regmap_common_cdb; + mlane = cdns_phy->phys[node].mlane; + ssc = cdns_phy->phys[node].ssc_mode; + num_lanes = cdns_phy->phys[node].num_lanes; /** - * First array value in link_cmn_vals must be of - * PHY_PLL_CFG register + * PHY configuration specific registers: + * link_cmn_vals depend on combination of PHY types being + * configured and are common for both PHY types, so array + * values should be same for [phy_t1][phy_t2][ssc] and + * [phy_t2][phy_t1][ssc]. + * xcvr_diag_vals also depend on combination of PHY types + * being configured, but these can be different for particular + * PHY type and are per lane. */ - regmap_field_write(cdns_phy->phy_pll_cfg, - reg_pairs[0].val); - - for (i = 1; i < num_regs; i++) - regmap_write(regmap, reg_pairs[i].off, - reg_pairs[i].val); - } + link_cmn_vals = init_data->link_cmn_vals[phy_t1][phy_t2][ssc]; + if (link_cmn_vals) { + reg_pairs = link_cmn_vals->reg_pairs; + num_regs = link_cmn_vals->num_regs; + regmap = cdns_phy->regmap_common_cdb; + + /** + * First array value in link_cmn_vals must be of + * PHY_PLL_CFG register + */ + regmap_field_write(cdns_phy->phy_pll_cfg, + reg_pairs[0].val); + + for (i = 1; i < num_regs; i++) + regmap_write(regmap, reg_pairs[i].off, + reg_pairs[i].val); + } - xcvr_diag_vals = init_data->xcvr_diag_vals[phy_t1][phy_t2][ssc]; - if (xcvr_diag_vals) { - reg_pairs = xcvr_diag_vals->reg_pairs; - num_regs = xcvr_diag_vals->num_regs; - for (i = 0; i < num_lanes; i++) { - regmap = cdns_phy->regmap_tx_lane_cdb[i + mlane]; - for (j = 0; j < num_regs; j++) - regmap_write(regmap, reg_pairs[j].off, - reg_pairs[j].val); + xcvr_diag_vals = init_data->xcvr_diag_vals[phy_t1][phy_t2][ssc]; + if (xcvr_diag_vals) { + reg_pairs = xcvr_diag_vals->reg_pairs; + num_regs = xcvr_diag_vals->num_regs; + for (i = 0; i < num_lanes; i++) { + regmap = cdns_phy->regmap_tx_lane_cdb[i + mlane]; + for (j = 0; j < num_regs; j++) + regmap_write(regmap, reg_pairs[j].off, + reg_pairs[j].val); + } } - } - /* PHY PCS common registers configurations */ - pcs_cmn_vals = init_data->pcs_cmn_vals[phy_t1][phy_t2][ssc]; - if (pcs_cmn_vals) { - reg_pairs = pcs_cmn_vals->reg_pairs; - num_regs = pcs_cmn_vals->num_regs; - regmap = cdns_phy->regmap_phy_pcs_common_cdb; - for (i = 0; i < num_regs; i++) - regmap_write(regmap, reg_pairs[i].off, - reg_pairs[i].val); - } + /* PHY PCS common registers configurations */ + pcs_cmn_vals = init_data->pcs_cmn_vals[phy_t1][phy_t2][ssc]; + if (pcs_cmn_vals) { + reg_pairs = pcs_cmn_vals->reg_pairs; + num_regs = pcs_cmn_vals->num_regs; + regmap = cdns_phy->regmap_phy_pcs_common_cdb; + for (i = 0; i < num_regs; i++) + regmap_write(regmap, reg_pairs[i].off, + reg_pairs[i].val); + } - /* PMA common registers configurations */ - cmn_vals = init_data->cmn_vals[phy_t1][phy_t2][ssc]; - if (cmn_vals) { - reg_pairs = cmn_vals->reg_pairs; - num_regs = cmn_vals->num_regs; - regmap = cdns_phy->regmap_common_cdb; - for (i = 0; i < num_regs; i++) - regmap_write(regmap, reg_pairs[i].off, - reg_pairs[i].val); - } + /* PMA common registers configurations */ + cmn_vals = init_data->cmn_vals[phy_t1][phy_t2][ssc]; + if (cmn_vals) { + reg_pairs = cmn_vals->reg_pairs; + num_regs = cmn_vals->num_regs; + regmap = cdns_phy->regmap_common_cdb; + for (i = 0; i < num_regs; i++) + regmap_write(regmap, reg_pairs[i].off, + reg_pairs[i].val); + } - /* PMA TX lane registers configurations */ - tx_ln_vals = init_data->tx_ln_vals[phy_t1][phy_t2][ssc]; - if (tx_ln_vals) { - reg_pairs = tx_ln_vals->reg_pairs; - num_regs = tx_ln_vals->num_regs; - for (i = 0; i < num_lanes; i++) { - regmap = cdns_phy->regmap_tx_lane_cdb[i + mlane]; - for (j = 0; j < num_regs; j++) - regmap_write(regmap, reg_pairs[j].off, - reg_pairs[j].val); + /* PMA TX lane registers configurations */ + tx_ln_vals = init_data->tx_ln_vals[phy_t1][phy_t2][ssc]; + if (tx_ln_vals) { + reg_pairs = tx_ln_vals->reg_pairs; + num_regs = tx_ln_vals->num_regs; + for (i = 0; i < num_lanes; i++) { + regmap = cdns_phy->regmap_tx_lane_cdb[i + mlane]; + for (j = 0; j < num_regs; j++) + regmap_write(regmap, reg_pairs[j].off, + reg_pairs[j].val); + } } - } - /* PMA RX lane registers configurations */ - rx_ln_vals = init_data->rx_ln_vals[phy_t1][phy_t2][ssc]; - if (rx_ln_vals) { - reg_pairs = rx_ln_vals->reg_pairs; - num_regs = rx_ln_vals->num_regs; - for (i = 0; i < num_lanes; i++) { - regmap = cdns_phy->regmap_rx_lane_cdb[i + mlane]; - for (j = 0; j < num_regs; j++) - regmap_write(regmap, reg_pairs[j].off, - reg_pairs[j].val); + /* PMA RX lane registers configurations */ + rx_ln_vals = init_data->rx_ln_vals[phy_t1][phy_t2][ssc]; + if (rx_ln_vals) { + reg_pairs = rx_ln_vals->reg_pairs; + num_regs = rx_ln_vals->num_regs; + for (i = 0; i < num_lanes; i++) { + regmap = cdns_phy->regmap_rx_lane_cdb[i + mlane]; + for (j = 0; j < num_regs; j++) + regmap_write(regmap, reg_pairs[j].off, + reg_pairs[j].val); + } } - } - reset_deassert_bulk(cdns_phy->phys[node].lnk_rst); + reset_deassert_bulk(cdns_phy->phys[node].lnk_rst); + } } /* Take the PHY out of reset */ @@ -575,6 +607,7 @@ static int cdns_torrent_phy_probe(struct udevice *dev) /* Get init data for this phy */ data = (struct cdns_torrent_data *)dev_get_driver_data(dev); cdns_phy->init_data = data; + cdns_phy->protocol_bitmask = 0; cdns_phy->phy_rst = devm_reset_control_get_by_index(dev, 0); if (IS_ERR(cdns_phy->phy_rst)) { @@ -677,6 +710,8 @@ static int cdns_torrent_phy_probe(struct udevice *dev) /* Get SSC mode */ ofnode_read_u32(child, "cdns,ssc-mode", &cdns_phy->phys[node].ssc_mode); + + cdns_phy->protocol_bitmask |= BIT(cdns_phy->phys[node].phy_type); node++; } 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/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/Kconfig b/drivers/pinctrl/Kconfig index 687fb339ea0..5e2808abc8a 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -263,6 +263,24 @@ config PINCTRL_ROCKCHIP_RV1108 both the GPIO definitions and pin control functions for each available multiplex function. +config PINCTRL_SX150X + bool "Semtech SX150x I2C GPIO expander pinctrl driver" + depends on DM && PINCTRL_FULL + help + Say yes here to provide support for Semtech SX150x-series I2C + GPIO expanders as pinctrl module. + Compatible models include: + - 8 bits: sx1508q, sx1502q + - 16 bits: sx1509q, sx1506q + +config SPL_PINCTRL_SX150X + bool "Semtech SX150x I2C GPIO expander pinctrl driver in SPL" + depends on DM && SPL_PINCTRL_FULL + help + This option is an SPL-variant of the PINCTRL_SX150X option. + See the help of PINCTRL_SX150X for details. + + config PINCTRL_SANDBOX bool "Sandbox pinctrl driver" depends on SANDBOX @@ -323,6 +341,14 @@ config SPL_PINCTRL_STMFX This option is an SPL-variant of the SPL_PINCTRL_STMFX option. See the help of PINCTRL_STMFX for details. +config PINCTRL_TH1520 + bool "T-Head TH1520 pinctrl driver" + depends on DM && PINCTRL_FULL + select PINCONF + help + Support pin multiplexing and configuration control blocks on the + T-Head TH1520 SoC. + config ASPEED_AST2500_PINCTRL bool "Aspeed AST2500 pin control driver" depends on DM && PINCTRL_GENERIC && ASPEED_AST2500 diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index a8eba656843..33ff7b95ef2 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -32,7 +32,9 @@ obj-$(CONFIG_PINCTRL_QE) += pinctrl-qe-io.o obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o obj-$(CONFIG_PINCTRL_STI) += pinctrl-sti.o obj-$(CONFIG_PINCTRL_STM32) += pinctrl_stm32.o +obj-$(CONFIG_$(PHASE_)PINCTRL_SX150X) += pinctrl-sx150x.o obj-$(CONFIG_$(PHASE_)PINCTRL_STMFX) += pinctrl-stmfx.o +obj-$(CONFIG_PINCTRL_TH1520) += pinctrl-th1520.o obj-y += broadcom/ obj-$(CONFIG_PINCTRL_ZYNQMP) += pinctrl-zynqmp.o obj-$(CONFIG_PINCTRL_STARFIVE) += starfive/ diff --git a/drivers/pinctrl/nxp/pinctrl-imx-mmio.c b/drivers/pinctrl/nxp/pinctrl-imx-mmio.c index 6ee108a0120..2f4228a9fc5 100644 --- a/drivers/pinctrl/nxp/pinctrl-imx-mmio.c +++ b/drivers/pinctrl/nxp/pinctrl-imx-mmio.c @@ -187,7 +187,6 @@ int imx_pinctrl_probe_mmio(struct udevice *dev) return -ENOMEM; priv->info = info; - info->mux_mask = ofnode_read_u32_default(node, "fsl,mux_mask", 0); /* * Refer to linux documentation for details: * Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.txt diff --git a/drivers/pinctrl/nxp/pinctrl-imx8ulp.c b/drivers/pinctrl/nxp/pinctrl-imx8ulp.c index 2df63625191..3e8c080d3fd 100644 --- a/drivers/pinctrl/nxp/pinctrl-imx8ulp.c +++ b/drivers/pinctrl/nxp/pinctrl-imx8ulp.c @@ -11,10 +11,12 @@ static struct imx_pinctrl_soc_info imx8ulp_pinctrl_soc_info0 = { .flags = ZERO_OFFSET_VALID | SHARE_MUX_CONF_REG | CFG_IBE_OBE, + .mux_mask = 0xf00, }; static struct imx_pinctrl_soc_info imx8ulp_pinctrl_soc_info1 = { .flags = ZERO_OFFSET_VALID | SHARE_MUX_CONF_REG | CFG_IBE_OBE, + .mux_mask = 0xf00, }; static const struct udevice_id imx8ulp_pinctrl_match[] = { diff --git a/drivers/pinctrl/nxp/pinctrl-imxrt.c b/drivers/pinctrl/nxp/pinctrl-imxrt.c index 39000ceb923..7e55d596248 100644 --- a/drivers/pinctrl/nxp/pinctrl-imxrt.c +++ b/drivers/pinctrl/nxp/pinctrl-imxrt.c @@ -11,6 +11,7 @@ static struct imx_pinctrl_soc_info imxrt_pinctrl_soc_info = { .flags = ZERO_OFFSET_VALID, + .mux_mask = 0x7, }; static const struct udevice_id imxrt_pinctrl_match[] = { diff --git a/drivers/pinctrl/nxp/pinctrl-vf610.c b/drivers/pinctrl/nxp/pinctrl-vf610.c index cbff8dcefd8..7d1b95eaa05 100644 --- a/drivers/pinctrl/nxp/pinctrl-vf610.c +++ b/drivers/pinctrl/nxp/pinctrl-vf610.c @@ -11,6 +11,7 @@ static struct imx_pinctrl_soc_info vf610_pinctrl_soc_info = { .flags = SHARE_MUX_CONF_REG | ZERO_OFFSET_VALID, + .mux_mask = 0x700000, }; static const struct udevice_id vf610_pinctrl_match[] = { diff --git a/drivers/pinctrl/pinctrl-sx150x.c b/drivers/pinctrl/pinctrl-sx150x.c new file mode 100644 index 00000000000..324d7af8fcd --- /dev/null +++ b/drivers/pinctrl/pinctrl-sx150x.c @@ -0,0 +1,902 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024, Exfo Inc - All Rights Reserved + * + * Author: Anis CHALI <anis.chali@exfo.com> + * inspired and adapted from linux driver of sx150x written by Gregory Bean + * <gbean@codeaurora.org> + */ + +#include <asm/gpio.h> +#include <dm.h> +#include <dm/device-internal.h> +#include <dm/device.h> +#include <dm/device_compat.h> +#include <dm/lists.h> +#include <dm/pinctrl.h> +#include <dt-bindings/gpio/gpio.h> +#include <i2c.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <log.h> +#include <power/regulator.h> +#include <regmap.h> + +#define err(format, arg...) printf("ERR:" format "\n", ##arg) +#define dbg(format, arg...) printf("DBG:" format "\n", ##arg) + +#define SX150X_PIN(_pin, _name) { .pin = _pin, .name = _name } + +/* The chip models of sx150x */ +enum { + SX150X_123 = 0, + SX150X_456, + SX150X_789, +}; + +enum { + SX150X_789_REG_MISC_AUTOCLEAR_OFF = 1 << 0, + SX150X_MAX_REGISTER = 0xad, + SX150X_IRQ_TYPE_EDGE_RISING = 0x1, + SX150X_IRQ_TYPE_EDGE_FALLING = 0x2, + SX150X_789_RESET_KEY1 = 0x12, + SX150X_789_RESET_KEY2 = 0x34, +}; + +struct sx150x_123_pri { + u8 reg_pld_mode; + u8 reg_pld_table0; + u8 reg_pld_table1; + u8 reg_pld_table2; + u8 reg_pld_table3; + u8 reg_pld_table4; + u8 reg_advanced; +}; + +struct sx150x_456_pri { + u8 reg_pld_mode; + u8 reg_pld_table0; + u8 reg_pld_table1; + u8 reg_pld_table2; + u8 reg_pld_table3; + u8 reg_pld_table4; + u8 reg_advanced; +}; + +struct sx150x_789_pri { + u8 reg_drain; + u8 reg_polarity; + u8 reg_clock; + u8 reg_misc; + u8 reg_reset; + u8 ngpios; +}; + +struct sx150x_pin_desc { + u32 pin; + u8 *name; +}; + +struct sx150x_device_data { + u8 model; + u8 reg_pullup; + u8 reg_pulldn; + u8 reg_dir; + u8 reg_data; + u8 reg_irq_mask; + u8 reg_irq_src; + u8 reg_sense; + u8 ngpios; + union { + struct sx150x_123_pri x123; + struct sx150x_456_pri x456; + struct sx150x_789_pri x789; + } pri; + const struct sx150x_pin_desc *pins; + unsigned int npins; +}; + +struct sx150x_pinctrl_priv { + char name[32]; + struct udevice *gpio; + struct udevice *i2c; + const struct sx150x_device_data *data; +}; + +static const struct sx150x_pin_desc sx150x_4_pins[] = { + SX150X_PIN(0, "gpio0"), SX150X_PIN(1, "gpio1"), SX150X_PIN(2, "gpio2"), + SX150X_PIN(3, "gpio3"), SX150X_PIN(4, "oscio"), +}; + +static const struct sx150x_pin_desc sx150x_8_pins[] = { + SX150X_PIN(0, "gpio0"), SX150X_PIN(1, "gpio1"), SX150X_PIN(2, "gpio2"), + SX150X_PIN(3, "gpio3"), SX150X_PIN(4, "gpio4"), SX150X_PIN(5, "gpio5"), + SX150X_PIN(6, "gpio6"), SX150X_PIN(7, "gpio7"), SX150X_PIN(8, "oscio"), +}; + +static const struct sx150x_pin_desc sx150x_16_pins[] = { + SX150X_PIN(0, "gpio0"), SX150X_PIN(1, "gpio1"), + SX150X_PIN(2, "gpio2"), SX150X_PIN(3, "gpio3"), + SX150X_PIN(4, "gpio4"), SX150X_PIN(5, "gpio5"), + SX150X_PIN(6, "gpio6"), SX150X_PIN(7, "gpio7"), + SX150X_PIN(8, "gpio8"), SX150X_PIN(9, "gpio9"), + SX150X_PIN(10, "gpio10"), SX150X_PIN(11, "gpio11"), + SX150X_PIN(12, "gpio12"), SX150X_PIN(13, "gpio13"), + SX150X_PIN(14, "gpio14"), SX150X_PIN(15, "gpio15"), + SX150X_PIN(16, "oscio"), +}; + +static const struct sx150x_device_data sx1501q_device_data = { + .model = SX150X_123, + .reg_pullup = 0x02, + .reg_pulldn = 0x03, + .reg_dir = 0x01, + .reg_data = 0x00, + .reg_irq_mask = 0x05, + .reg_irq_src = 0x08, + .reg_sense = 0x07, + .pri.x123 = { + .reg_pld_mode = 0x10, + .reg_pld_table0 = 0x11, + .reg_pld_table2 = 0x13, + .reg_advanced = 0xad, + }, + .ngpios = 4, + .pins = sx150x_4_pins, + .npins = 4, /* oscio not available */ +}; + +static const struct sx150x_device_data sx1502q_device_data = { + .model = SX150X_123, + .reg_pullup = 0x02, + .reg_pulldn = 0x03, + .reg_dir = 0x01, + .reg_data = 0x00, + .reg_irq_mask = 0x05, + .reg_irq_src = 0x08, + .reg_sense = 0x06, + .pri.x123 = { + .reg_pld_mode = 0x10, + .reg_pld_table0 = 0x11, + .reg_pld_table1 = 0x12, + .reg_pld_table2 = 0x13, + .reg_pld_table3 = 0x14, + .reg_pld_table4 = 0x15, + .reg_advanced = 0xad, + }, + .ngpios = 8, + .pins = sx150x_8_pins, + .npins = 8, /* oscio not available */ +}; + +static const struct sx150x_device_data sx1503q_device_data = { + .model = SX150X_123, + .reg_pullup = 0x04, + .reg_pulldn = 0x06, + .reg_dir = 0x02, + .reg_data = 0x00, + .reg_irq_mask = 0x08, + .reg_irq_src = 0x0e, + .reg_sense = 0x0a, + .pri.x123 = { + .reg_pld_mode = 0x20, + .reg_pld_table0 = 0x22, + .reg_pld_table1 = 0x24, + .reg_pld_table2 = 0x26, + .reg_pld_table3 = 0x28, + .reg_pld_table4 = 0x2a, + .reg_advanced = 0xad, + }, + .ngpios = 16, + .pins = sx150x_16_pins, + .npins = 16, /* oscio not available */ +}; + +static const struct sx150x_device_data sx1504q_device_data = { + .model = SX150X_456, + .reg_pullup = 0x02, + .reg_pulldn = 0x03, + .reg_dir = 0x01, + .reg_data = 0x00, + .reg_irq_mask = 0x05, + .reg_irq_src = 0x08, + .reg_sense = 0x07, + .pri.x456 = { + .reg_pld_mode = 0x10, + .reg_pld_table0 = 0x11, + .reg_pld_table2 = 0x13, + }, + .ngpios = 4, + .pins = sx150x_4_pins, + .npins = 4, /* oscio not available */ +}; + +static const struct sx150x_device_data sx1505q_device_data = { + .model = SX150X_456, + .reg_pullup = 0x02, + .reg_pulldn = 0x03, + .reg_dir = 0x01, + .reg_data = 0x00, + .reg_irq_mask = 0x05, + .reg_irq_src = 0x08, + .reg_sense = 0x06, + .pri.x456 = { + .reg_pld_mode = 0x10, + .reg_pld_table0 = 0x11, + .reg_pld_table1 = 0x12, + .reg_pld_table2 = 0x13, + .reg_pld_table3 = 0x14, + .reg_pld_table4 = 0x15, + }, + .ngpios = 8, + .pins = sx150x_8_pins, + .npins = 8, /* oscio not available */ +}; + +static const struct sx150x_device_data sx1506q_device_data = { + .model = SX150X_456, + .reg_pullup = 0x04, + .reg_pulldn = 0x06, + .reg_dir = 0x02, + .reg_data = 0x00, + .reg_irq_mask = 0x08, + .reg_irq_src = 0x0e, + .reg_sense = 0x0a, + .pri.x456 = { + .reg_pld_mode = 0x20, + .reg_pld_table0 = 0x22, + .reg_pld_table1 = 0x24, + .reg_pld_table2 = 0x26, + .reg_pld_table3 = 0x28, + .reg_pld_table4 = 0x2a, + .reg_advanced = 0xad, + }, + .ngpios = 16, + .pins = sx150x_16_pins, + .npins = 16, /* oscio not available */ +}; + +static const struct sx150x_device_data sx1507q_device_data = { + .model = SX150X_789, + .reg_pullup = 0x03, + .reg_pulldn = 0x04, + .reg_dir = 0x07, + .reg_data = 0x08, + .reg_irq_mask = 0x09, + .reg_irq_src = 0x0b, + .reg_sense = 0x0a, + .pri.x789 = { + .reg_drain = 0x05, + .reg_polarity = 0x06, + .reg_clock = 0x0d, + .reg_misc = 0x0e, + .reg_reset = 0x7d, + }, + .ngpios = 4, + .pins = sx150x_4_pins, + .npins = ARRAY_SIZE(sx150x_4_pins), +}; + +static const struct sx150x_device_data sx1508q_device_data = { + .model = SX150X_789, + .reg_pullup = 0x03, + .reg_pulldn = 0x04, + .reg_dir = 0x07, + .reg_data = 0x08, + .reg_irq_mask = 0x09, + .reg_irq_src = 0x0c, + .reg_sense = 0x0a, + .pri.x789 = { + .reg_drain = 0x05, + .reg_polarity = 0x06, + .reg_clock = 0x0f, + .reg_misc = 0x10, + .reg_reset = 0x7d, + }, + .ngpios = 8, + .pins = sx150x_8_pins, + .npins = ARRAY_SIZE(sx150x_8_pins), +}; + +static const struct sx150x_device_data sx1509q_device_data = { + .model = SX150X_789, + .reg_pullup = 0x06, + .reg_pulldn = 0x08, + .reg_dir = 0x0e, + .reg_data = 0x10, + .reg_irq_mask = 0x12, + .reg_irq_src = 0x18, + .reg_sense = 0x14, + .pri.x789 = { + .reg_drain = 0x0a, + .reg_polarity = 0x0c, + .reg_clock = 0x1e, + .reg_misc = 0x1f, + .reg_reset = 0x7d, + }, + .ngpios = 16, + .pins = sx150x_16_pins, + .npins = ARRAY_SIZE(sx150x_16_pins), +}; + +static bool sx150x_pin_is_oscio(struct sx150x_pinctrl_priv *pctl, + unsigned int pin) +{ + if (pin >= pctl->data->npins) + return false; + + /* OSCIO pin is only present in 789 devices */ + if (pctl->data->model != SX150X_789) + return false; + + return !strcmp(pctl->data->pins[pin].name, "oscio"); +} + +static int sx150x_reg_width(struct sx150x_pinctrl_priv *pctl, unsigned int reg) +{ + const struct sx150x_device_data *data = pctl->data; + + if (reg == data->reg_sense) { + /* + * RegSense packs two bits of configuration per GPIO, + * so we'd need to read twice as many bits as there + * are GPIO in our chip + */ + return 2 * data->ngpios; + } else if ((data->model == SX150X_789 && + (reg == data->pri.x789.reg_misc || + reg == data->pri.x789.reg_clock || + reg == data->pri.x789.reg_reset)) || + (data->model == SX150X_123 && + reg == data->pri.x123.reg_advanced) || + (data->model == SX150X_456 && data->pri.x456.reg_advanced && + reg == data->pri.x456.reg_advanced)) { + return 8; + } else { + return data->ngpios; + } +} + +static unsigned int sx150x_maybe_swizzle(struct sx150x_pinctrl_priv *pctl, + unsigned int reg, unsigned int val) +{ + unsigned int a, b; + const struct sx150x_device_data *data = pctl->data; + + /* + * Whereas SX1509 presents RegSense in a simple layout as such: + * reg [ f f e e d d c c ] + * reg 1 [ b b a a 9 9 8 8 ] + * reg 2 [ 7 7 6 6 5 5 4 4 ] + * reg 3 [ 3 3 2 2 1 1 0 0 ] + * + * SX1503 and SX1506 deviate from that data layout, instead storing + * their contents as follows: + * + * reg [ f f e e d d c c ] + * reg 1 [ 7 7 6 6 5 5 4 4 ] + * reg 2 [ b b a a 9 9 8 8 ] + * reg 3 [ 3 3 2 2 1 1 0 0 ] + * + * so, taking that into account, we swap two + * inner bytes of a 4-byte result + */ + + if (reg == data->reg_sense && data->ngpios == 16 && + (data->model == SX150X_123 || data->model == SX150X_456)) { + a = val & 0x00ff0000; + b = val & 0x0000ff00; + + val &= 0xff0000ff; + val |= b << 8; + val |= a >> 8; + } + + return val; +} + +/* + * In order to mask the differences between 16 and 8 bit expander + * devices we set up a sligthly ficticious regmap that pretends to be + * a set of 32-bit (to accommodate RegSenseLow/RegSenseHigh + * pair/quartet) registers and transparently reconstructs those + * registers via multiple I2C/SMBus reads + * + * This way the rest of the driver code, interfacing with the chip via + * regmap API, can work assuming that each GPIO pin is represented by + * a group of bits at an offset proportional to GPIO number within a + * given register. + */ +static int sx150x_reg_read(struct sx150x_pinctrl_priv *pctl, unsigned int reg, + unsigned int *result) +{ + int ret, n; + const int width = sx150x_reg_width(pctl, reg); + unsigned int idx, val; + + /* + * There are four potential cases covered by this function: + * + * 1) 8-pin chip, single configuration bit register + * + * This is trivial the code below just needs to read: + * reg [ 7 6 5 4 3 2 1 0 ] + * + * 2) 8-pin chip, double configuration bit register (RegSense) + * + * The read will be done as follows: + * reg [ 7 7 6 6 5 5 4 4 ] + * reg 1 [ 3 3 2 2 1 1 0 0 ] + * + * 3) 16-pin chip, single configuration bit register + * + * The read will be done as follows: + * reg [ f e d c b a 9 8 ] + * reg 1 [ 7 6 5 4 3 2 1 0 ] + * + * 4) 16-pin chip, double configuration bit register (RegSense) + * + * The read will be done as follows: + * reg [ f f e e d d c c ] + * reg 1 [ b b a a 9 9 8 8 ] + * reg 2 [ 7 7 6 6 5 5 4 4 ] + * reg 3 [ 3 3 2 2 1 1 0 0 ] + */ + + for (n = width, val = 0, idx = reg; n > 0; n -= 8, idx) { + val <<= 8; + + ret = dm_i2c_reg_read(pctl->i2c, idx); + if (ret < 0) + return ret; + + val |= ret; + } + + *result = sx150x_maybe_swizzle(pctl, reg, val); + + return 0; +} + +static int sx150x_reg_write(struct sx150x_pinctrl_priv *pctl, unsigned int reg, + unsigned int val) +{ + int ret, n; + const int width = sx150x_reg_width(pctl, reg); + + val = sx150x_maybe_swizzle(pctl, reg, val); + + n = (width - 1) & ~7; + do { + const u8 byte = (val >> n) & 0xff; + + ret = dm_i2c_reg_write(pctl->i2c, reg, byte); + if (ret < 0) + return ret; + + reg; + n -= 8; + } while (n >= 0); + + return 0; +} + +static unsigned int sx150x_read(struct sx150x_pinctrl_priv *pctl, uint reg) +{ + int ret; + unsigned int res; + + ret = sx150x_reg_read(pctl, reg, &res); + if (ret) { + err("%s: failed to read reg(%x) with %d", pctl->name, reg, ret); + return ret; + } + + return res; +} + +static int sx150x_write(struct sx150x_pinctrl_priv *pctl, uint reg, uint val) +{ + return sx150x_reg_write(pctl, reg, val); +} + +static int sx150x_write_bits(struct sx150x_pinctrl_priv *pctl, uint reg, + uint mask, uint val) +{ + int orig, tmp; + + orig = sx150x_read(pctl, reg); + if (orig < 0) + return orig; + + tmp = orig & ~mask; + tmp |= val & mask; + + return sx150x_write(pctl, reg, tmp); +} + +static int sx150x_reset(struct udevice *dev) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev); + int err; + + err = sx150x_write(pctl, pctl->data->pri.x789.reg_reset, + SX150X_789_RESET_KEY1); + if (err < 0) + return err; + + err = sx150x_write(pctl, pctl->data->pri.x789.reg_reset, + SX150X_789_RESET_KEY2); + return err; +} + +static int sx150x_init_misc(struct udevice *dev) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev); + u8 reg, value; + + switch (pctl->data->model) { + case SX150X_789: + reg = pctl->data->pri.x789.reg_misc; + value = 0x0; + break; + case SX150X_456: + reg = pctl->data->pri.x456.reg_advanced; + value = 0x00; + + /* + * Only SX1506 has RegAdvanced, SX1504/5 are expected + * to initialize this offset to zero + */ + if (!reg) + return 0; + break; + case SX150X_123: + reg = pctl->data->pri.x123.reg_advanced; + value = 0x00; + break; + default: + WARN(1, "Unknown chip model %d\n", pctl->data->model); + return -EINVAL; + } + + return sx150x_write(pctl, reg, value); +} + +static int sx150x_init_hw(struct udevice *dev) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev); + const u8 reg[] = { + [SX150X_789] = pctl->data->pri.x789.reg_polarity, + [SX150X_456] = pctl->data->pri.x456.reg_pld_mode, + [SX150X_123] = pctl->data->pri.x123.reg_pld_mode, + }; + int err; + + if (pctl->data->model == SX150X_789 && + dev_read_bool(dev, "semtech,probe-reset")) { + err = sx150x_reset(dev); + if (err < 0) + return err; + } + + err = sx150x_init_misc(dev); + if (err < 0) + return err; + + /* Set all pins to work in normal mode */ + return sx150x_write(pctl, reg[pctl->data->model], 0); +} + +static int sx150x_gpio_get_value(struct udevice *dev, unsigned int offset) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev->parent); + + if (sx150x_pin_is_oscio(pctl, offset)) + return -EINVAL; + + int val = sx150x_read(pctl, pctl->data->reg_data); + + return !!(val & BIT(offset)); +} + +static int sx150x_gpio_set(struct udevice *dev, unsigned int offset, int value) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev->parent); + + return sx150x_write_bits(pctl, pctl->data->reg_data, BIT(offset), + value ? BIT(offset) : 0); +} + +static int sx150x_gpio_oscio_set(struct udevice *dev, int value) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev->parent); + + return sx150x_write(pctl, pctl->data->pri.x789.reg_clock, + (value ? 0x1f : 0x10)); +} + +static int sx150x_gpio_set_value(struct udevice *dev, unsigned int offset, + int value) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev->parent); + + if (sx150x_pin_is_oscio(pctl, offset)) + sx150x_gpio_oscio_set(dev->parent, value); + else + sx150x_gpio_set(dev->parent, offset, value); + + return 0; +} + +static int sx150x_gpio_get_direction(struct udevice *dev, unsigned int offset) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev->parent); + int val; + + if (sx150x_pin_is_oscio(pctl, offset)) + return GPIOF_OUTPUT; + + val = sx150x_read(pctl, pctl->data->reg_data); + if (val < 0) + return val; + + if (val & BIT(offset)) + return GPIOF_INPUT; + + return GPIOF_OUTPUT; +} + +static int sx150x_gpio_direction_input(struct udevice *dev, unsigned int offset) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev->parent); + + if (sx150x_pin_is_oscio(pctl, offset)) + return -EINVAL; + + return sx150x_write_bits(pctl, pctl->data->reg_dir, BIT(offset), + BIT(offset)); +} + +static int sx150x_gpio_direction_output(struct udevice *dev, + unsigned int offset, int value) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev->parent); + int ret; + + if (sx150x_pin_is_oscio(pctl, offset)) + return sx150x_gpio_oscio_set(dev, value); + + ret = sx150x_write_bits(pctl, pctl->data->reg_dir, BIT(offset), 0); + if (ret < 0) + return ret; + + return sx150x_gpio_set(dev, offset, value); +} + +static int sx150x_gpio_probe(struct udevice *dev) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev->parent); + struct gpio_dev_priv *uc_priv; + + uc_priv = dev_get_uclass_priv(dev); + uc_priv->bank_name = pctl->name; + uc_priv->gpio_count = pctl->data->ngpios; + + return 0; +} + +static struct dm_gpio_ops sx150x_gpio_ops = { + .get_value = sx150x_gpio_get_value, + .set_value = sx150x_gpio_set_value, + .get_function = sx150x_gpio_get_direction, + .direction_input = sx150x_gpio_direction_input, + .direction_output = sx150x_gpio_direction_output, +}; + +static struct driver sx150x_gpio_driver = { + .name = "sx150x-gpio", + .id = UCLASS_GPIO, + .probe = sx150x_gpio_probe, + .ops = &sx150x_gpio_ops, +}; + +static const struct udevice_id sx150x_pinctrl_of_match[] = { + { .compatible = "semtech,sx1501q", + .data = (ulong)&sx1501q_device_data }, + { .compatible = "semtech,sx1502q", + .data = (ulong)&sx1502q_device_data }, + { .compatible = "semtech,sx1503q", + .data = (ulong)&sx1503q_device_data }, + { .compatible = "semtech,sx1504q", + .data = (ulong)&sx1504q_device_data }, + { .compatible = "semtech,sx1505q", + .data = (ulong)&sx1505q_device_data }, + { .compatible = "semtech,sx1506q", + .data = (ulong)&sx1506q_device_data }, + { .compatible = "semtech,sx1507q", + .data = (ulong)&sx1507q_device_data }, + { .compatible = "semtech,sx1508q", + .data = (ulong)&sx1508q_device_data }, + { .compatible = "semtech,sx1509q", + .data = (ulong)&sx1509q_device_data }, + {}, +}; + +static const struct pinconf_param sx150x_conf_params[] = { + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, + { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 }, + { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 }, + { "output", PIN_CONFIG_OUTPUT, 0 }, +}; + +static int sx150x_pinctrl_get_pins_count(struct udevice *dev) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev); + + return pctl->data->ngpios; +} + +static const char *sx150x_pinctrl_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev); + static char pin_name[PINNAME_SIZE]; + + snprintf(pin_name, PINNAME_SIZE, "%s", pctl->data->pins[selector].name); + return pin_name; +} + +static int sx150x_pinctrl_conf_set(struct udevice *dev, unsigned int pin, + unsigned int param, unsigned int arg) +{ + int ret; + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev); + + if (sx150x_pin_is_oscio(pctl, pin)) { + if (param == PIN_CONFIG_OUTPUT) { + ret = sx150x_gpio_direction_output(pctl->gpio, pin, + arg); + if (ret < 0) + return ret; + } else { + return -EOPNOTSUPP; + } + } + + switch (param) { + case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: + case PIN_CONFIG_BIAS_DISABLE: + ret = sx150x_write_bits(pctl, pctl->data->reg_pulldn, BIT(pin), + 0); + if (ret < 0) + return ret; + + ret = sx150x_write_bits(pctl, pctl->data->reg_pullup, BIT(pin), + 0); + if (ret < 0) + return ret; + break; + + case PIN_CONFIG_BIAS_PULL_UP: + ret = sx150x_write_bits(pctl, pctl->data->reg_pullup, BIT(pin), + BIT(pin)); + if (ret < 0) + return ret; + + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + ret = sx150x_write_bits(pctl, pctl->data->reg_pulldn, BIT(pin), + BIT(pin)); + if (ret < 0) + return ret; + break; + + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + if (pctl->data->model != SX150X_789 || + sx150x_pin_is_oscio(pctl, pin)) + return -EOPNOTSUPP; + + ret = sx150x_write_bits(pctl, pctl->data->pri.x789.reg_drain, + BIT(pin), BIT(pin)); + if (ret < 0) + return ret; + + break; + + case PIN_CONFIG_DRIVE_PUSH_PULL: + if (pctl->data->model != SX150X_789 || + sx150x_pin_is_oscio(pctl, pin)) + return 0; + + ret = sx150x_write_bits(pctl, pctl->data->pri.x789.reg_drain, + BIT(pin), 0); + if (ret < 0) + return ret; + + break; + + case PIN_CONFIG_OUTPUT: + ret = sx150x_gpio_direction_output(pctl->gpio, pin, arg); + if (ret < 0) + return ret; + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int sx150x_pinctrl_bind(struct udevice *dev) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_plat(dev); + int ret, reg; + + if (!dev_read_bool(dev, "gpio-controller")) + return 0; + + reg = (int)dev_read_addr_ptr(dev); + + ret = device_bind(dev, &sx150x_gpio_driver, dev_read_name(dev), NULL, + dev_ofnode(dev), &pctl->gpio); + if (ret) + return ret; + + return 0; +} + +static int sx150x_pinctrl_probe(struct udevice *dev) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev); + const struct sx150x_device_data *drv_data = + (const struct sx150x_device_data *)dev_get_driver_data(dev); + int ret, reg; + + if (!drv_data) + return -ENOENT; + + pctl->data = drv_data; + + reg = (int)dev_read_addr_ptr(dev); + ret = dm_i2c_probe(dev->parent, reg, 0, &pctl->i2c); + if (ret) { + err("Cannot find I2C chip %02x (%d)", reg, ret); + return ret; + } + + ret = sx150x_init_hw(dev); + if (ret) { + err("Cannot initialize GPIO expander at %02x with %d", reg, + ret); + return ret; + } + + snprintf(pctl->name, 32, "gpio-ext@%x_", reg); + + return 0; +} + +static struct pinctrl_ops sx150x_pinctrl_ops = { + .set_state = pinctrl_generic_set_state, + .get_pins_count = sx150x_pinctrl_get_pins_count, + .get_pin_name = sx150x_pinctrl_get_pin_name, +#if CONFIG_IS_ENABLED(PINCONF) + .pinconf_set = sx150x_pinctrl_conf_set, + .pinconf_num_params = ARRAY_SIZE(sx150x_conf_params), + .pinconf_params = sx150x_conf_params, +#endif +}; + +U_BOOT_DRIVER(sx150x_pinctrl) = { + .name = "sx150x-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = sx150x_pinctrl_of_match, + .priv_auto = sizeof(struct sx150x_pinctrl_priv), + .ops = &sx150x_pinctrl_ops, + .probe = sx150x_pinctrl_probe, + .bind = sx150x_pinctrl_bind, +}; diff --git a/drivers/pinctrl/pinctrl-th1520.c b/drivers/pinctrl/pinctrl-th1520.c new file mode 100644 index 00000000000..be7e508f8a4 --- /dev/null +++ b/drivers/pinctrl/pinctrl-th1520.c @@ -0,0 +1,700 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Pinctrl driver for the T-Head TH1520 SoC + * + * Copyright (C) 2023 Emil Renner Berthing <emil.renner.berthing@canonical.com> + * Copyright (C) 2025 Yao Zi <ziyao@disroot.org> + */ + +#include <asm/io.h> +#include <clk.h> +#include <dm.h> +#include <dm/pinctrl.h> +#include <linux/bitops.h> +#include <linux/string.h> +#include <malloc.h> + +#define TH1520_PADCFG_IE BIT(9) +#define TH1520_PADCFG_SL BIT(8) +#define TH1520_PADCFG_ST BIT(7) +#define TH1520_PADCFG_SPU BIT(6) +#define TH1520_PADCFG_PS BIT(5) +#define TH1520_PADCFG_PE BIT(4) +#define TH1520_PADCFG_BIAS (TH1520_PADCFG_SPU | TH1520_PADCFG_PS | TH1520_PADCFG_PE) +#define TH1520_PADCFG_DS GENMASK(3, 0) + +#define TH1520_PULL_DOWN_OHM 44000 /* typ. 44kOhm */ +#define TH1520_PULL_UP_OHM 48000 /* typ. 48kOhm */ +#define TH1520_PULL_STRONG_OHM 2100 /* typ. 2.1kOhm */ + +#define TH1520_PAD_NO_PADCFG BIT(0) + +enum th1520_muxtype { + TH1520_MUX_____, + TH1520_MUX_GPIO, + TH1520_MUX_PWM, + TH1520_MUX_UART, + TH1520_MUX_IR, + TH1520_MUX_I2C, + TH1520_MUX_SPI, + TH1520_MUX_QSPI, + TH1520_MUX_SDIO, + TH1520_MUX_AUD, + TH1520_MUX_I2S, + TH1520_MUX_MAC0, + TH1520_MUX_MAC1, + TH1520_MUX_DPU0, + TH1520_MUX_DPU1, + TH1520_MUX_ISP, + TH1520_MUX_HDMI, + TH1520_MUX_BSEL, + TH1520_MUX_DBG, + TH1520_MUX_CLK, + TH1520_MUX_JTAG, + TH1520_MUX_ISO, + TH1520_MUX_FUSE, + TH1520_MUX_RST, +}; + +static const char *const th1520_muxtype_string[] = { + [TH1520_MUX_GPIO] = "gpio", + [TH1520_MUX_PWM] = "pwm", + [TH1520_MUX_UART] = "uart", + [TH1520_MUX_IR] = "ir", + [TH1520_MUX_I2C] = "i2c", + [TH1520_MUX_SPI] = "spi", + [TH1520_MUX_QSPI] = "qspi", + [TH1520_MUX_SDIO] = "sdio", + [TH1520_MUX_AUD] = "audio", + [TH1520_MUX_I2S] = "i2s", + [TH1520_MUX_MAC0] = "gmac0", + [TH1520_MUX_MAC1] = "gmac1", + [TH1520_MUX_DPU0] = "dpu0", + [TH1520_MUX_DPU1] = "dpu1", + [TH1520_MUX_ISP] = "isp", + [TH1520_MUX_HDMI] = "hdmi", + [TH1520_MUX_BSEL] = "bootsel", + [TH1520_MUX_DBG] = "debug", + [TH1520_MUX_CLK] = "clock", + [TH1520_MUX_JTAG] = "jtag", + [TH1520_MUX_ISO] = "iso7816", + [TH1520_MUX_FUSE] = "efuse", + [TH1520_MUX_RST] = "reset", +}; + +struct th1520_pin_desc { + unsigned int number; + const char *name; + enum th1520_muxtype muxes[6]; + u8 flags; +}; + +struct th1520_pad_group { + unsigned int npins; + const struct th1520_pin_desc *pins; + const char *name; +}; + +struct th1520_pinctrl { + const struct th1520_pad_group *group; + void __iomem *base; + struct pinctrl_dev *pctl; +}; + +static enum th1520_muxtype th1520_muxtype_get(const char *str) +{ + enum th1520_muxtype mt; + + for (mt = TH1520_MUX_GPIO; mt < ARRAY_SIZE(th1520_muxtype_string); mt++) { + if (!strcmp(str, th1520_muxtype_string[mt])) + return mt; + } + return TH1520_MUX_____; +} + +#define TH1520_PAD(_nr, _name, m0, m1, m2, m3, m4, m5, _flags) \ + { \ + .number = _nr, \ + .name = #_name, \ + .muxes = { \ + TH1520_MUX_##m0, TH1520_MUX_##m1, \ + TH1520_MUX_##m2, TH1520_MUX_##m3, \ + TH1520_MUX_##m4, TH1520_MUX_##m5 \ + }, \ + .flags = _flags, \ + } + +static bool th1520_pad_no_padcfg(const struct th1520_pin_desc *pin) +{ + return pin->flags & TH1520_PAD_NO_PADCFG; +} + +static const struct th1520_pin_desc th1520_group1_pins[] = { + TH1520_PAD(0, OSC_CLK_IN, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(1, OSC_CLK_OUT, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(2, SYS_RST_N, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(3, RTC_CLK_IN, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(4, RTC_CLK_OUT, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + /* skip number 5 so we can calculate register offsets and shifts from the pin number */ + TH1520_PAD(6, TEST_MODE, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(7, DEBUG_MODE, DBG, ____, ____, GPIO, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(8, POR_SEL, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(9, I2C_AON_SCL, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(10, I2C_AON_SDA, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(11, CPU_JTG_TCLK, JTAG, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(12, CPU_JTG_TMS, JTAG, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(13, CPU_JTG_TDI, JTAG, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(14, CPU_JTG_TDO, JTAG, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(15, CPU_JTG_TRST, JTAG, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(16, AOGPIO_7, CLK, AUD, ____, GPIO, ____, ____, 0), + TH1520_PAD(17, AOGPIO_8, UART, AUD, IR, GPIO, ____, ____, 0), + TH1520_PAD(18, AOGPIO_9, UART, AUD, IR, GPIO, ____, ____, 0), + TH1520_PAD(19, AOGPIO_10, CLK, AUD, ____, GPIO, ____, ____, 0), + TH1520_PAD(20, AOGPIO_11, GPIO, AUD, ____, ____, ____, ____, 0), + TH1520_PAD(21, AOGPIO_12, GPIO, AUD, ____, ____, ____, ____, 0), + TH1520_PAD(22, AOGPIO_13, GPIO, AUD, ____, ____, ____, ____, 0), + TH1520_PAD(23, AOGPIO_14, GPIO, AUD, ____, ____, ____, ____, 0), + TH1520_PAD(24, AOGPIO_15, GPIO, AUD, ____, ____, ____, ____, 0), + TH1520_PAD(25, AUDIO_PA0, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(26, AUDIO_PA1, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(27, AUDIO_PA2, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(28, AUDIO_PA3, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(29, AUDIO_PA4, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(30, AUDIO_PA5, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(31, AUDIO_PA6, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(32, AUDIO_PA7, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(33, AUDIO_PA8, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(34, AUDIO_PA9, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(35, AUDIO_PA10, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(36, AUDIO_PA11, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(37, AUDIO_PA12, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(38, AUDIO_PA13, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(39, AUDIO_PA14, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(40, AUDIO_PA15, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(41, AUDIO_PA16, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(42, AUDIO_PA17, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(43, AUDIO_PA27, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(44, AUDIO_PA28, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(45, AUDIO_PA29, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(46, AUDIO_PA30, AUD, RST, ____, GPIO, ____, ____, 0), +}; + +static const struct th1520_pin_desc th1520_group2_pins[] = { + TH1520_PAD(0, QSPI1_SCLK, QSPI, ISO, ____, GPIO, FUSE, ____, 0), + TH1520_PAD(1, QSPI1_CSN0, QSPI, ____, I2C, GPIO, FUSE, ____, 0), + TH1520_PAD(2, QSPI1_D0_MOSI, QSPI, ISO, I2C, GPIO, FUSE, ____, 0), + TH1520_PAD(3, QSPI1_D1_MISO, QSPI, ISO, ____, GPIO, FUSE, ____, 0), + TH1520_PAD(4, QSPI1_D2_WP, QSPI, ISO, UART, GPIO, FUSE, ____, 0), + TH1520_PAD(5, QSPI1_D3_HOLD, QSPI, ISO, UART, GPIO, ____, ____, 0), + TH1520_PAD(6, I2C0_SCL, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(7, I2C0_SDA, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(8, I2C1_SCL, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(9, I2C1_SDA, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(10, UART1_TXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(11, UART1_RXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(12, UART4_TXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(13, UART4_RXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(14, UART4_CTSN, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(15, UART4_RTSN, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(16, UART3_TXD, DBG, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(17, UART3_RXD, DBG, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(18, GPIO0_18, GPIO, I2C, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(19, GPIO0_19, GPIO, I2C, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(20, GPIO0_20, GPIO, UART, IR, ____, DPU0, DPU1, 0), + TH1520_PAD(21, GPIO0_21, GPIO, UART, IR, ____, DPU0, DPU1, 0), + TH1520_PAD(22, GPIO0_22, GPIO, JTAG, I2C, ____, DPU0, DPU1, 0), + TH1520_PAD(23, GPIO0_23, GPIO, JTAG, I2C, ____, DPU0, DPU1, 0), + TH1520_PAD(24, GPIO0_24, GPIO, JTAG, QSPI, ____, DPU0, DPU1, 0), + TH1520_PAD(25, GPIO0_25, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(26, GPIO0_26, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(27, GPIO0_27, GPIO, ____, I2C, ____, DPU0, DPU1, 0), + TH1520_PAD(28, GPIO0_28, GPIO, ____, I2C, ____, DPU0, DPU1, 0), + TH1520_PAD(29, GPIO0_29, GPIO, ____, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(30, GPIO0_30, GPIO, ____, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(31, GPIO0_31, GPIO, ____, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(32, GPIO1_0, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(33, GPIO1_1, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(34, GPIO1_2, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(35, GPIO1_3, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(36, GPIO1_4, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(37, GPIO1_5, GPIO, ____, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(38, GPIO1_6, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(39, GPIO1_7, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(40, GPIO1_8, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(41, GPIO1_9, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(42, GPIO1_10, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(43, GPIO1_11, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(44, GPIO1_12, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(45, GPIO1_13, GPIO, UART, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(46, GPIO1_14, GPIO, UART, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(47, GPIO1_15, GPIO, UART, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(48, GPIO1_16, GPIO, UART, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(49, CLK_OUT_0, BSEL, CLK, ____, GPIO, ____, ____, 0), + TH1520_PAD(50, CLK_OUT_1, BSEL, CLK, ____, GPIO, ____, ____, 0), + TH1520_PAD(51, CLK_OUT_2, BSEL, CLK, ____, GPIO, ____, ____, 0), + TH1520_PAD(52, CLK_OUT_3, BSEL, CLK, ____, GPIO, ____, ____, 0), + TH1520_PAD(53, GPIO1_21, JTAG, ____, ISP, GPIO, ____, ____, 0), + TH1520_PAD(54, GPIO1_22, JTAG, ____, ISP, GPIO, ____, ____, 0), + TH1520_PAD(55, GPIO1_23, JTAG, ____, ISP, GPIO, ____, ____, 0), + TH1520_PAD(56, GPIO1_24, JTAG, ____, ISP, GPIO, ____, ____, 0), + TH1520_PAD(57, GPIO1_25, JTAG, ____, ISP, GPIO, ____, ____, 0), + TH1520_PAD(58, GPIO1_26, GPIO, ____, ISP, ____, ____, ____, 0), + TH1520_PAD(59, GPIO1_27, GPIO, ____, ISP, ____, ____, ____, 0), + TH1520_PAD(60, GPIO1_28, GPIO, ____, ISP, ____, ____, ____, 0), + TH1520_PAD(61, GPIO1_29, GPIO, ____, ISP, ____, ____, ____, 0), + TH1520_PAD(62, GPIO1_30, GPIO, ____, ISP, ____, ____, ____, 0), +}; + +static const struct th1520_pin_desc th1520_group3_pins[] = { + TH1520_PAD(0, UART0_TXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(1, UART0_RXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(2, QSPI0_SCLK, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(3, QSPI0_CSN0, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(4, QSPI0_CSN1, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(5, QSPI0_D0_MOSI, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(6, QSPI0_D1_MISO, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(7, QSPI0_D2_WP, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(8, QSPI1_D3_HOLD, QSPI, ____, I2S, GPIO, ____, ____, 0), + TH1520_PAD(9, I2C2_SCL, I2C, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(10, I2C2_SDA, I2C, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(11, I2C3_SCL, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(12, I2C3_SDA, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(13, GPIO2_13, GPIO, SPI, ____, ____, ____, ____, 0), + TH1520_PAD(14, SPI_SCLK, SPI, UART, IR, GPIO, ____, ____, 0), + TH1520_PAD(15, SPI_CSN, SPI, UART, IR, GPIO, ____, ____, 0), + TH1520_PAD(16, SPI_MOSI, SPI, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(17, SPI_MISO, SPI, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(18, GPIO2_18, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(19, GPIO2_19, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(20, GPIO2_20, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(21, GPIO2_21, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(22, GPIO2_22, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(23, GPIO2_23, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(24, GPIO2_24, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(25, GPIO2_25, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(26, SDIO0_WPRTN, SDIO, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(27, SDIO0_DETN, SDIO, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(28, SDIO1_WPRTN, SDIO, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(29, SDIO1_DETN, SDIO, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(30, GPIO2_30, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(31, GPIO2_31, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(32, GPIO3_0, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(33, GPIO3_1, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(34, GPIO3_2, GPIO, PWM, ____, ____, ____, ____, 0), + TH1520_PAD(35, GPIO3_3, GPIO, PWM, ____, ____, ____, ____, 0), + TH1520_PAD(36, HDMI_SCL, HDMI, PWM, ____, GPIO, ____, ____, 0), + TH1520_PAD(37, HDMI_SDA, HDMI, PWM, ____, GPIO, ____, ____, 0), + TH1520_PAD(38, HDMI_CEC, HDMI, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(39, GMAC0_TX_CLK, MAC0, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(40, GMAC0_RX_CLK, MAC0, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(41, GMAC0_TXEN, MAC0, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(42, GMAC0_TXD0, MAC0, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(43, GMAC0_TXD1, MAC0, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(44, GMAC0_TXD2, MAC0, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(45, GMAC0_TXD3, MAC0, I2C, ____, GPIO, ____, ____, 0), + TH1520_PAD(46, GMAC0_RXDV, MAC0, I2C, ____, GPIO, ____, ____, 0), + TH1520_PAD(47, GMAC0_RXD0, MAC0, I2C, ____, GPIO, ____, ____, 0), + TH1520_PAD(48, GMAC0_RXD1, MAC0, I2C, ____, GPIO, ____, ____, 0), + TH1520_PAD(49, GMAC0_RXD2, MAC0, SPI, ____, GPIO, ____, ____, 0), + TH1520_PAD(50, GMAC0_RXD3, MAC0, SPI, ____, GPIO, ____, ____, 0), + TH1520_PAD(51, GMAC0_MDC, MAC0, SPI, MAC1, GPIO, ____, ____, 0), + TH1520_PAD(52, GMAC0_MDIO, MAC0, SPI, MAC1, GPIO, ____, ____, 0), + TH1520_PAD(53, GMAC0_COL, MAC0, PWM, ____, GPIO, ____, ____, 0), + TH1520_PAD(54, GMAC0_CRS, MAC0, PWM, ____, GPIO, ____, ____, 0), +}; + +static const struct th1520_pad_group th1520_group1 = { + .name = "th1520-group1", + .pins = th1520_group1_pins, + .npins = ARRAY_SIZE(th1520_group1_pins), +}; + +static const struct th1520_pad_group th1520_group2 = { + .name = "th1520-group2", + .pins = th1520_group2_pins, + .npins = ARRAY_SIZE(th1520_group2_pins), +}; + +static const struct th1520_pad_group th1520_group3 = { + .name = "th1520-group3", + .pins = th1520_group3_pins, + .npins = ARRAY_SIZE(th1520_group3_pins), +}; + +static void __iomem *th1520_padcfg(struct th1520_pinctrl *thp, + unsigned int pin) +{ + return thp->base + 4 * (pin / 2); +} + +static unsigned int th1520_padcfg_shift(unsigned int pin) +{ + return 16 * (pin & BIT(0)); +} + +static void __iomem *th1520_muxcfg(struct th1520_pinctrl *thp, + unsigned int pin) +{ + return thp->base + 0x400 + 4 * (pin / 8); +} + +static unsigned int th1520_muxcfg_shift(unsigned int pin) +{ + return 4 * (pin & GENMASK(2, 0)); +} + +static const u8 th1520_drive_strength_in_ma[16] = { + 1, 2, 3, 5, 7, 8, 10, 12, 13, 15, 16, 18, 20, 21, 23, 25, +}; + +static u16 th1520_drive_strength_from_ma(u32 arg) +{ + u16 ds; + + for (ds = 0; ds < TH1520_PADCFG_DS; ds++) { + if (arg <= th1520_drive_strength_in_ma[ds]) + return ds; + } + return TH1520_PADCFG_DS; +} + +static int th1520_padcfg_rmw(struct th1520_pinctrl *thp, unsigned int pin, + u32 mask, u32 value) +{ + void __iomem *padcfg = th1520_padcfg(thp, pin); + unsigned int shift = th1520_padcfg_shift(pin); + u32 tmp; + + mask <<= shift; + value <<= shift; + + tmp = readl_relaxed(padcfg); + tmp = (tmp & ~mask) | value; + writel_relaxed(tmp, padcfg); + + return 0; +} + +static int th1520_pinconf_apply_one(struct th1520_pinctrl *thp, + const struct th1520_pin_desc *desc, + enum pin_config_param param, u32 arg) + +{ + u16 mask = 0, value = 0; + + if (th1520_pad_no_padcfg(desc)) + return -EOPNOTSUPP; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + mask |= TH1520_PADCFG_BIAS; + value &= ~TH1520_PADCFG_BIAS; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (arg == 0) + return -EOPNOTSUPP; + mask |= TH1520_PADCFG_BIAS; + value &= ~TH1520_PADCFG_BIAS; + value |= TH1520_PADCFG_PE; + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (arg == 0) + return -EOPNOTSUPP; + mask |= TH1520_PADCFG_BIAS; + value &= ~TH1520_PADCFG_BIAS; + if (arg == TH1520_PULL_STRONG_OHM) + value |= TH1520_PADCFG_SPU; + else + value |= TH1520_PADCFG_PE | TH1520_PADCFG_PS; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + mask |= TH1520_PADCFG_DS; + value &= ~TH1520_PADCFG_DS; + value |= th1520_drive_strength_from_ma(arg); + break; + case PIN_CONFIG_INPUT_ENABLE: + mask |= TH1520_PADCFG_IE; + if (arg) + value |= TH1520_PADCFG_IE; + else + value &= ~TH1520_PADCFG_IE; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + mask |= TH1520_PADCFG_ST; + if (arg) + value |= TH1520_PADCFG_ST; + else + value &= ~TH1520_PADCFG_ST; + break; + case PIN_CONFIG_SLEW_RATE: + mask |= TH1520_PADCFG_SL; + if (arg) + value |= TH1520_PADCFG_SL; + else + value &= ~TH1520_PADCFG_SL; + break; + default: + return -EOPNOTSUPP; + } + + return th1520_padcfg_rmw(thp, desc->number, mask, value); +} + +static int th1520_pinmux_apply_one(struct th1520_pinctrl *thp, + const struct th1520_pin_desc *desc, + enum th1520_muxtype muxtype) +{ + void __iomem *muxcfg = th1520_muxcfg(thp, desc->number); + unsigned int shift = th1520_muxcfg_shift(desc->number); + u32 mask, value, tmp; + + for (value = 0; value < ARRAY_SIZE(desc->muxes); value++) { + if (desc->muxes[value] == muxtype) + break; + } + if (value == ARRAY_SIZE(desc->muxes)) { + pr_err("invalid mux %s for pin \"%s\"\n", + th1520_muxtype_string[muxtype], desc->name); + return -EINVAL; + } + + mask = GENMASK(3, 0) << shift; + value = value << shift; + + tmp = readl_relaxed(muxcfg); + tmp = (tmp & ~mask) | value; + writel_relaxed(tmp, muxcfg); + + return 0; +} + +const struct pinconf_param th1520_pinconf_params[] = { + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, + { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, + { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 }, + { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 }, + { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 }, + { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 }, + { "slew-rate", PIN_CONFIG_SLEW_RATE, 0 }, +}; + +static const struct th1520_pin_desc * +th1520_pinctrl_search_pin(struct th1520_pinctrl *thp, + const char *name) +{ + const struct th1520_pad_group *pg = thp->group; + int i; + + for (i = 0; i < pg->npins; i++) { + if (!strcmp(pg->pins[i].name, name)) + return &pg->pins[i]; + } + + return NULL; +} + +static int th1520_pinctrl_apply_group(struct th1520_pinctrl *thp, ofnode group) +{ + struct th1520_pin_desc const **pins; + enum th1520_muxtype muxtype; + int pin_count, ret, i, j; + const char *muxname; + + pin_count = ofnode_read_string_count(group, "pins"); + if (pin_count < 0) { + pr_err("missing property pins"); + return -EINVAL; + } + + pins = calloc(pin_count, sizeof(pins[0])); + if (!pins) + return -ENOMEM; + + for (i = 0; i < pin_count; i++) { + const char *pinname; + + ret = ofnode_read_string_index(group, "pins", i, &pinname); + if (ret) + goto out; + + pins[i] = th1520_pinctrl_search_pin(thp, pinname); + if (!pins[i]) { + pr_err("unknown pin name \"%s\"\n", pinname); + goto out; + } + } + + for (i = 0; i < ARRAY_SIZE(th1520_pinconf_params); i++) { + const struct pinconf_param *param = &th1520_pinconf_params[i]; + u32 val; + + ret = ofnode_read_u32(group, param->property, &val); + if (ret == -EINVAL) + continue; + else if (ret) + val = param->default_value; + + for (j = 0; j < pin_count; j++) { + ret = th1520_pinconf_apply_one(thp, pins[j], + param->param, val); + if (ret) { + pr_err("failed to apply pinconf for \"%s\": %d\n", + pins[j]->name, ret); + goto out; + } + } + } + + muxname = ofnode_read_string(group, "function"); + if (!muxname) + goto out; + + muxtype = th1520_muxtype_get(muxname); + if (!muxtype) { + pr_err("invalid mux type \"%s\"", muxname); + ret = -EINVAL; + goto out; + } + + for (i = 0; i < pin_count; i++) { + ret = th1520_pinmux_apply_one(thp, pins[i], muxtype); + if (ret) { + pr_err("failed to set pinmux function: %d\n", ret); + break; + } + } + +out: + free(pins); + + return ret; +} + +static int th1520_pinctrl_set_state(struct udevice *dev, struct udevice *pcfg) +{ + struct th1520_pinctrl *thp = dev_get_priv(dev); + ofnode group; + int ret = 0; + + dev_for_each_subnode(group, pcfg) { + ret = th1520_pinctrl_apply_group(thp, group); + if (ret) { + pr_err("failed to apply pin group \"%s\": %d\n", + ofnode_get_name(group), ret); + break; + } + } + + return ret; +} + +static int th1520_pinctrl_get_pins_count(struct udevice *dev) +{ + struct th1520_pinctrl *thp = dev_get_priv(dev); + + return thp->group->npins; +} + +static const char *th1520_pinctrl_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + struct th1520_pinctrl *p = dev_get_priv(dev); + + if (selector >= p->group->npins) + return ERR_PTR(-EINVAL); + + return p->group->pins[selector].name; +} + +static int th1520_pinctrl_get_pin_muxing(struct udevice *dev, + unsigned int selector, + char *buf, int size) +{ + struct th1520_pinctrl *thp = dev_get_priv(dev); + const struct th1520_pad_group *group = thp->group; + const struct th1520_pin_desc *desc; + void __iomem *muxcfg; + unsigned int shift; + u32 val; + + if (selector >= group->npins) + return -EINVAL; + + desc = &group->pins[selector]; + if (th1520_pad_no_padcfg(desc)) { + strlcpy(buf, "unsupported", size - 1); + return 0; + } + + muxcfg = th1520_muxcfg(thp, desc->number); + shift = th1520_muxcfg_shift(desc->number); + + val = (readl_relaxed(muxcfg) >> shift) & GENMASK(3, 0); + strlcpy(buf, th1520_muxtype_string[desc->muxes[val]], size); + + return 0; +} + +static const struct pinctrl_ops th1520_pinctrl_ops = { + .get_pins_count = th1520_pinctrl_get_pins_count, + .get_pin_name = th1520_pinctrl_get_pin_name, + .get_pin_muxing = th1520_pinctrl_get_pin_muxing, + .set_state = th1520_pinctrl_set_state, +}; + +static int th1520_pinctrl_probe(struct udevice *dev) +{ + struct th1520_pinctrl *thp = dev_get_priv(dev); + struct clk clk; + u32 pin_group; + int ret; + + thp->base = dev_read_addr_ptr(dev); + if (!thp->base) + return -EINVAL; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) { + pr_err("failed to enable pinctrl clock: %d\n", ret); + return ret; + } + + ret = dev_read_u32(dev, "thead,pad-group", &pin_group); + if (ret) { + pr_err("failed to read thead,pad-group property: %d\n", ret); + return ret; + } + + switch (pin_group) { + case 1: + thp->group = &th1520_group1; + break; + case 2: + thp->group = &th1520_group2; + break; + case 3: + thp->group = &th1520_group3; + break; + default: + pr_err("invalid thead,pad-group property: %u\n", pin_group); + return -EINVAL; + } + + return 0; +} + +static const struct udevice_id th1520_pinctrl_ids[] = { + { .compatible = "thead,th1520-pinctrl"}, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(th1520_pinctrl) = { + .name = "th1520-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = th1520_pinctrl_ids, + .probe = th1520_pinctrl_probe, + .priv_auto = sizeof(struct th1520_pinctrl), + .ops = &th1520_pinctrl_ops, +}; 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/axp221.c b/drivers/power/axp221.c index c22ca03f469..f5daa243082 100644 --- a/drivers/power/axp221.c +++ b/drivers/power/axp221.c @@ -10,6 +10,7 @@ */ #include <command.h> +#include <env.h> #include <errno.h> #include <asm/arch/pmic_bus.h> #include <axp_pmic.h> 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/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/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/scsi/scsi-uclass.c b/drivers/scsi/scsi-uclass.c index 1ee8236c05c..3eb6069649f 100644 --- a/drivers/scsi/scsi-uclass.c +++ b/drivers/scsi/scsi-uclass.c @@ -10,7 +10,9 @@ #define LOG_CATEGORY UCLASS_SCSI +#include <blk.h> #include <dm.h> +#include <part.h> #include <scsi.h> int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb) @@ -23,6 +25,34 @@ int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb) return ops->exec(dev, pccb); } +int scsi_get_blk_by_uuid(const char *uuid, + struct blk_desc **blk_desc_ptr, + struct disk_partition *part_info_ptr) +{ + static int is_scsi_scanned; + struct blk_desc *blk; + int i, ret; + + if (!is_scsi_scanned) { + scsi_scan(false /* no verbose */); + is_scsi_scanned = 1; + } + + for (i = 0; i < blk_find_max_devnum(UCLASS_SCSI) + 1; i++) { + ret = blk_get_desc(UCLASS_SCSI, i, &blk); + if (ret) + continue; + + ret = part_get_info_by_uuid(blk, uuid, part_info_ptr); + if (ret > 0) { + *blk_desc_ptr = blk; + return 0; + } + } + + return -1; +} + int scsi_bus_reset(struct udevice *dev) { struct scsi_ops *ops = scsi_get_ops(dev); 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/spi/fsl_dspi.c b/drivers/spi/fsl_dspi.c index f2393c041f4..545561ad116 100644 --- a/drivers/spi/fsl_dspi.c +++ b/drivers/spi/fsl_dspi.c @@ -123,8 +123,10 @@ static uint dspi_read32(uint flags, uint *addr) static void dspi_write32(uint flags, uint *addr, uint val) { - flags & DSPI_FLAG_REGMAP_ENDIAN_BIG ? - out_be32(addr, val) : out_le32(addr, val); + if (flags & DSPI_FLAG_REGMAP_ENDIAN_BIG) + out_be32(addr, val); + else + out_le32(addr, val); } static void dspi_halt(struct fsl_dspi_priv *priv, u8 halt) diff --git a/drivers/tpm/sandbox_common.c b/drivers/tpm/sandbox_common.c index 596e0156389..9d386fc32e5 100644 --- a/drivers/tpm/sandbox_common.c +++ b/drivers/tpm/sandbox_common.c @@ -9,6 +9,7 @@ #include <tpm-v1.h> #include <tpm-v2.h> +#include <linux/string.h> #include <asm/unaligned.h> #include "sandbox_common.h" 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/common/Makefile b/drivers/usb/common/Makefile index 4c597c166c6..db8f35c10c4 100644 --- a/drivers/usb/common/Makefile +++ b/drivers/usb/common/Makefile @@ -4,6 +4,8 @@ # obj-$(CONFIG_$(PHASE_)DM_USB) += common.o +obj-$(CONFIG_USB_DWC2) += dwc2_core.o +obj-$(CONFIG_USB_GADGET_DWC2_OTG) += dwc2_core.o obj-$(CONFIG_USB_ISP1760) += usb_urb.o obj-$(CONFIG_USB_MUSB_HOST) += usb_urb.o obj-$(CONFIG_USB_MUSB_GADGET) += usb_urb.o diff --git a/drivers/usb/common/dwc2_core.c b/drivers/usb/common/dwc2_core.c new file mode 100644 index 00000000000..63062d5cc94 --- /dev/null +++ b/drivers/usb/common/dwc2_core.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2024-2025, Kongyang Liu <seashell11234455@gmail.com> + */ + +#include <linux/bitfield.h> +#include <linux/errno.h> +#include <linux/io.h> +#include <wait_bit.h> + +#include "dwc2_core.h" + +int dwc2_core_reset(struct dwc2_core_regs *regs) +{ + u32 snpsid; + int ret; + bool host_mode = false; + + if (!(readl(®s->global_regs.gotgctl) & GOTGCTL_CONID_B) || + (readl(®s->global_regs.gusbcfg) & GUSBCFG_FORCEDEVMODE)) + host_mode = true; + + /* Core Soft Reset */ + snpsid = readl(®s->global_regs.gsnpsid); + writel(GRSTCTL_CSFTRST, ®s->global_regs.grstctl); + if (FIELD_GET(GSNPSID_VER_MASK, snpsid) < 0x420a) { + ret = wait_for_bit_le32(®s->global_regs.grstctl, GRSTCTL_CSFTRST, + false, 1000, false); + if (ret) { + log_warning("%s: Waiting for GRSTCTL_CSFTRST timeout\n", __func__); + return ret; + } + } else { + ret = wait_for_bit_le32(®s->global_regs.grstctl, GRSTCTL_CSFTRST_DONE, + true, 1000, false); + if (ret) { + log_warning("%s: Waiting for GRSTCTL_CSFTRST_DONE timeout\n", __func__); + return ret; + } + clrsetbits_le32(®s->global_regs.grstctl, GRSTCTL_CSFTRST, GRSTCTL_CSFTRST_DONE); + } + + /* Wait for AHB master IDLE state. */ + ret = wait_for_bit_le32(®s->global_regs.grstctl, GRSTCTL_AHBIDLE, + true, 1000, false); + if (ret) { + log_warning("%s: Waiting for GRSTCTL_AHBIDLE timeout\n", __func__); + return ret; + } + + if (host_mode) { + ret = wait_for_bit_le32(®s->global_regs.gintsts, GINTSTS_CURMODE_HOST, + host_mode, 1000, false); + if (ret) { + log_warning("%s: Waiting for GINTSTS_CURMODE_HOST timeout\n", __func__); + return ret; + } + } + + return 0; +} + +int dwc2_flush_tx_fifo(struct dwc2_core_regs *regs, const int num) +{ + int ret; + + log_debug("Flush Tx FIFO %d\n", num); + + /* Wait for AHB master IDLE state */ + ret = wait_for_bit_le32(®s->global_regs.grstctl, GRSTCTL_AHBIDLE, true, 1000, false); + if (ret) { + log_warning("%s: Waiting for GRSTCTL_AHBIDLE timeout\n", __func__); + return ret; + } + + writel(GRSTCTL_TXFFLSH | FIELD_PREP(GRSTCTL_TXFNUM_MASK, num), ®s->global_regs.grstctl); + + ret = wait_for_bit_le32(®s->global_regs.grstctl, GRSTCTL_TXFFLSH, false, 1000, false); + if (ret) { + log_warning("%s: Waiting for GRSTCTL_TXFFLSH timeout\n", __func__); + return ret; + } + + /* + * Wait for at least 3 PHY clocks. + * + * The PHY clock frequency can be configured to 6/30/48/60 MHz + * based on the speed mode. A fixed delay of 1us ensures that the + * wait time is sufficient even at the lowest PHY clock frequency + * (6 MHz), where 1us corresponds to twice the duration of 3 PHY + * clocks. + */ + udelay(1); + + return 0; +} + +int dwc2_flush_rx_fifo(struct dwc2_core_regs *regs) +{ + int ret; + + log_debug("Flush Rx FIFO\n"); + + /* Wait for AHB master IDLE state */ + ret = wait_for_bit_le32(®s->global_regs.grstctl, GRSTCTL_AHBIDLE, true, 1000, false); + if (ret) { + log_warning("%s: Waiting for GRSTCTL_AHBIDLE timeout\n", __func__); + return ret; + } + + writel(GRSTCTL_RXFFLSH, ®s->global_regs.grstctl); + + ret = wait_for_bit_le32(®s->global_regs.grstctl, GRSTCTL_RXFFLSH, false, 1000, false); + if (ret) { + log_warning("%s: Waiting for GRSTCTL_RXFFLSH timeout\n", __func__); + return ret; + } + + /* + * Wait for at least 3 PHY clocks. + * + * The PHY clock frequency can be configured to 6/30/48/60 MHz + * based on the speed mode. A fixed delay of 1us ensures that the + * wait time is sufficient even at the lowest PHY clock frequency + * (6 MHz), where 1us corresponds to twice the duration of 3 PHY + * clocks. + */ + udelay(1); + + return 0; +} diff --git a/drivers/usb/common/dwc2_core.h b/drivers/usb/common/dwc2_core.h new file mode 100644 index 00000000000..1897ad7cb54 --- /dev/null +++ b/drivers/usb/common/dwc2_core.h @@ -0,0 +1,560 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com> + * + */ + +#ifndef __DWC2_CORE_H_ +#define __DWC2_CORE_H_ + +#include <linux/bitops.h> + +struct dwc2_global_regs { + u32 gotgctl; /* 0x000 */ + u32 gotgint; + u32 gahbcfg; + u32 gusbcfg; + u32 grstctl; /* 0x010 */ + u32 gintsts; + u32 gintmsk; + u32 grxstsr; + u32 grxstsp; /* 0x020 */ + u32 grxfsiz; + u32 gnptxfsiz; + u32 gnptxsts; + u32 gi2cctl; /* 0x030 */ + u32 gpvndctl; + u32 ggpio; + u32 guid; + u32 gsnpsid; /* 0x040 */ + u32 ghwcfg1; + u32 ghwcfg2; + u32 ghwcfg3; + u32 ghwcfg4; /* 0x050 */ + u32 glpmcfg; + u32 gpwrdn; + u32 gdfifocfg; + u32 gadpctl; /* 0x060 */ + u32 grefclk; + u32 gintmsk2; + u32 gintsts2; + u8 _pad_from_0x70_to_0x100[0x100 - 0x70]; + u32 hptxfsiz; /* 0x100 */ + u32 dptxfsizn[15]; + u8 _pad_from_0x140_to_0x400[0x400 - 0x140]; +}; + +struct dwc2_hc_regs { + u32 hcchar; /* 0x500 + 0x20 * ch */ + u32 hcsplt; + u32 hcint; + u32 hcintmsk; + u32 hctsiz; + u32 hcdma; + u32 reserved; + u32 hcdmab; +}; + +struct dwc2_host_regs { + u32 hcfg; /* 0x400 */ + u32 hfir; + u32 hfnum; + u32 _pad_0x40c; + u32 hptxsts; /* 0x410 */ + u32 haint; + u32 haintmsk; + u32 hflbaddr; + u8 _pad_from_0x420_to_0x440[0x440 - 0x420]; + u32 hprt0; /* 0x440 */ + u8 _pad_from_0x444_to_0x500[0x500 - 0x444]; + struct dwc2_hc_regs hc[16]; /* 0x500 */ + u8 _pad_from_0x700_to_0x800[0x800 - 0x700]; +}; + +/* Device Logical IN Endpoint-Specific Registers */ +struct dwc2_dev_in_endp { + u32 diepctl; /* 0x900 + 0x20 * ep */ + u32 reserved0; + u32 diepint; + u32 reserved1; + u32 dieptsiz; + u32 diepdma; + u32 reserved2; + u32 diepdmab; +}; + +/* Device Logical OUT Endpoint-Specific Registers */ +struct dwc2_dev_out_endp { + u32 doepctl; /* 0xB00 + 0x20 * ep */ + u32 reserved0; + u32 doepint; + u32 reserved1; + u32 doeptsiz; + u32 doepdma; + u32 reserved2; + u32 doepdmab; +}; + +struct dwc2_device_regs { + u32 dcfg; /* 0x800 */ + u32 dctl; + u32 dsts; + u32 _pad_0x80c; + u32 diepmsk; /* 0x810 */ + u32 doepmsk; + u32 daint; + u32 daintmsk; + u32 dtknqr1; /* 0x820 */ + u32 dtknqr2; + u32 dvbusdis; + u32 dvbuspulse; + u32 dtknqr3; /* 0x830 */ + u32 dtknqr4; + u8 _pad_from_0x838_to_0x900[0x900 - 0x838]; + struct dwc2_dev_in_endp in_endp[16]; /* 0x900 */ + struct dwc2_dev_out_endp out_endp[16]; /* 0xB00 */ +}; + +struct dwc2_core_regs { + struct dwc2_global_regs global_regs; /* 0x000 */ + struct dwc2_host_regs host_regs; /* 0x400 */ + struct dwc2_device_regs device_regs; /* 0x800 */ + u8 _pad_from_0xd00_to_0xe00[0xe00 - 0xd00]; + u32 pcgcctl; /* 0xe00 */ + u8 _pad_from_0xe04_to_0x1000[0x1000 - 0xe04]; + u8 ep_fifo[16][0x1000]; /* 0x1000 */ +}; + +int dwc2_core_reset(struct dwc2_core_regs *regs); +int dwc2_flush_tx_fifo(struct dwc2_core_regs *regs, const int num); +int dwc2_flush_rx_fifo(struct dwc2_core_regs *regs); + +/* Core Global Register */ +#define GOTGCTL_CHIRPEN BIT(27) +#define GOTGCTL_MULT_VALID_BC_MASK GENMASK(26, 22) +#define GOTGCTL_CURMODE_HOST BIT(21) +#define GOTGCTL_OTGVER BIT(20) +#define GOTGCTL_BSESVLD BIT(19) +#define GOTGCTL_ASESVLD BIT(18) +#define GOTGCTL_DBNC_SHORT BIT(17) +#define GOTGCTL_CONID_B BIT(16) +#define GOTGCTL_DBNCE_FLTR_BYPASS BIT(15) +#define GOTGCTL_DEVHNPEN BIT(11) +#define GOTGCTL_HSTSETHNPEN BIT(10) +#define GOTGCTL_HNPREQ BIT(9) +#define GOTGCTL_HSTNEGSCS BIT(8) +#define GOTGCTL_BVALOVAL BIT(7) +#define GOTGCTL_BVALOEN BIT(6) +#define GOTGCTL_AVALOVAL BIT(5) +#define GOTGCTL_AVALOEN BIT(4) +#define GOTGCTL_VBVALOVAL BIT(3) +#define GOTGCTL_VBVALOEN BIT(2) +#define GOTGCTL_SESREQ BIT(1) +#define GOTGCTL_SESREQSCS BIT(0) + +#define GOTGINT_DBNCE_DONE BIT(19) +#define GOTGINT_A_DEV_TOUT_CHG BIT(18) +#define GOTGINT_HST_NEG_DET BIT(17) +#define GOTGINT_HST_NEG_SUC_STS_CHNG BIT(9) +#define GOTGINT_SES_REQ_SUC_STS_CHNG BIT(8) +#define GOTGINT_SES_END_DET BIT(2) + +#define GAHBCFG_AHB_SINGLE BIT(23) +#define GAHBCFG_NOTI_ALL_DMA_WRIT BIT(22) +#define GAHBCFG_REM_MEM_SUPP BIT(21) +#define GAHBCFG_P_TXF_EMP_LVL BIT(8) +#define GAHBCFG_NP_TXF_EMP_LVL BIT(7) +#define GAHBCFG_DMA_EN BIT(5) +#define GAHBCFG_HBSTLEN_MASK GENMASK(4, 1) +#define GAHBCFG_HBSTLEN_SINGLE 0 +#define GAHBCFG_HBSTLEN_INCR 1 +#define GAHBCFG_HBSTLEN_INCR4 3 +#define GAHBCFG_HBSTLEN_INCR8 5 +#define GAHBCFG_HBSTLEN_INCR16 7 +#define GAHBCFG_GLBL_INTR_EN BIT(0) +#define GAHBCFG_CTRL_MASK (GAHBCFG_P_TXF_EMP_LVL | \ + GAHBCFG_NP_TXF_EMP_LVL | \ + GAHBCFG_DMA_EN | \ + GAHBCFG_GLBL_INTR_EN) + +#define GUSBCFG_FORCEDEVMODE BIT(30) +#define GUSBCFG_FORCEHOSTMODE BIT(29) +#define GUSBCFG_TXENDDELAY BIT(28) +#define GUSBCFG_ICTRAFFICPULLREMOVE BIT(27) +#define GUSBCFG_ICUSBCAP BIT(26) +#define GUSBCFG_ULPI_INT_PROT_DIS BIT(25) +#define GUSBCFG_INDICATORPASSTHROUGH BIT(24) +#define GUSBCFG_INDICATORCOMPLEMENT BIT(23) +#define GUSBCFG_TERMSELDLPULSE BIT(22) +#define GUSBCFG_ULPI_INT_VBUS_IND BIT(21) +#define GUSBCFG_ULPI_EXT_VBUS_DRV BIT(20) +#define GUSBCFG_ULPI_CLK_SUSP_M BIT(19) +#define GUSBCFG_ULPI_AUTO_RES BIT(18) +#define GUSBCFG_ULPI_FS_LS BIT(17) +#define GUSBCFG_OTG_UTMI_FS_SEL BIT(16) +#define GUSBCFG_PHY_LP_CLK_SEL BIT(15) +#define GUSBCFG_USBTRDTIM_MASK GENMASK(14, 10) +#define GUSBCFG_HNPCAP BIT(9) +#define GUSBCFG_SRPCAP BIT(8) +#define GUSBCFG_DDRSEL BIT(7) +#define GUSBCFG_PHYSEL BIT(6) +#define GUSBCFG_FSINTF BIT(5) +#define GUSBCFG_ULPI_UTMI_SEL BIT(4) +#define GUSBCFG_PHYIF16 BIT(3) +#define GUSBCFG_TOUTCAL_MASK GENMASK(2, 0) + +#define GRSTCTL_AHBIDLE BIT(31) +#define GRSTCTL_DMAREQ BIT(30) +#define GRSTCTL_CSFTRST_DONE BIT(29) +#define GRSTCTL_TXFNUM_MASK GENMASK(10, 6) +#define GRSTCTL_TXFFLSH BIT(5) +#define GRSTCTL_RXFFLSH BIT(4) +#define GRSTCTL_IN_TKNQ_FLSH BIT(3) +#define GRSTCTL_FRMCNTRRST BIT(2) +#define GRSTCTL_HSFTRST BIT(1) +#define GRSTCTL_CSFTRST BIT(0) +#define GRSTCTL_TXFNUM_ALL 0x10 + +#define GINTSTS_WKUPINT BIT(31) +#define GINTSTS_SESSREQINT BIT(30) +#define GINTSTS_DISCONNINT BIT(29) +#define GINTSTS_CONIDSTSCHNG BIT(28) +#define GINTSTS_LPMTRANRCVD BIT(27) +#define GINTSTS_PTXFEMP BIT(26) +#define GINTSTS_HCHINT BIT(25) +#define GINTSTS_PRTINT BIT(24) +#define GINTSTS_RESETDET BIT(23) +#define GINTSTS_FET_SUSP BIT(22) +#define GINTSTS_INCOMPL_IP BIT(21) +#define GINTSTS_INCOMPL_SOOUT BIT(21) +#define GINTSTS_INCOMPL_SOIN BIT(20) +#define GINTSTS_OEPINT BIT(19) +#define GINTSTS_IEPINT BIT(18) +#define GINTSTS_EPMIS BIT(17) +#define GINTSTS_RESTOREDONE BIT(16) +#define GINTSTS_EOPF BIT(15) +#define GINTSTS_ISOUTDROP BIT(14) +#define GINTSTS_ENUMDONE BIT(13) +#define GINTSTS_USBRST BIT(12) +#define GINTSTS_USBSUSP BIT(11) +#define GINTSTS_ERLYSUSP BIT(10) +#define GINTSTS_I2CINT BIT(9) +#define GINTSTS_ULPI_CK_INT BIT(8) +#define GINTSTS_GOUTNAKEFF BIT(7) +#define GINTSTS_GINNAKEFF BIT(6) +#define GINTSTS_NPTXFEMP BIT(5) +#define GINTSTS_RXFLVL BIT(4) +#define GINTSTS_SOF BIT(3) +#define GINTSTS_OTGINT BIT(2) +#define GINTSTS_MODEMIS BIT(1) +#define GINTSTS_CURMODE_HOST BIT(0) + +#define GRXSTS_FN_MASK GENMASK(31, 25) +#define GRXSTS_PKTSTS_MASK GENMASK(20, 17) +#define GRXSTS_PKTSTS_GLOBALOUTNAK 1 +#define GRXSTS_PKTSTS_OUTRX 2 +#define GRXSTS_PKTSTS_HCHIN 2 +#define GRXSTS_PKTSTS_OUTDONE 3 +#define GRXSTS_PKTSTS_HCHIN_XFER_COMP 3 +#define GRXSTS_PKTSTS_SETUPDONE 4 +#define GRXSTS_PKTSTS_DATATOGGLEERR 5 +#define GRXSTS_PKTSTS_SETUPRX 6 +#define GRXSTS_PKTSTS_HCHHALTED 7 +#define GRXSTS_DPID_MASK GENMASK(16, 15) +#define GRXSTS_BYTECNT_MASK GENMASK(14, 4) +#define GRXSTS_HCHNUM_MASK GENMASK(3, 0) + +#define GRXFSIZ_DEPTH_MASK GENMASK(15, 0) + +#define GI2CCTL_BSYDNE BIT(31) +#define GI2CCTL_RW BIT(30) +#define GI2CCTL_I2CDATSE0 BIT(28) +#define GI2CCTL_I2CDEVADDR_MASK GENMASK(27, 26) +#define GI2CCTL_I2CSUSPCTL BIT(25) +#define GI2CCTL_ACK BIT(24) +#define GI2CCTL_I2CEN BIT(23) +#define GI2CCTL_ADDR_MASK GENMASK(22, 16) +#define GI2CCTL_REGADDR_MASK GENMASK(15, 8) +#define GI2CCTL_RWDATA_MASK GENMASK(7, 0) + +#define GGPIO_STM32_OTG_GCCFG_IDEN BIT(22) +#define GGPIO_STM32_OTG_GCCFG_VBDEN BIT(21) +#define GGPIO_STM32_OTG_GCCFG_PWRDWN BIT(16) + +#define GSNPSID_ID_MASK GENMASK(31, 16) +#define GSNPSID_OTG_ID 0x4f54 +#define GSNPSID_VER_MASK GENMASK(15, 0) + +#define GHWCFG2_OTG_ENABLE_IC_USB BIT(31) +#define GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK GENMASK(30, 26) +#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK GENMASK(25, 24) +#define GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK GENMASK(23, 22) +#define GHWCFG2_MULTI_PROC_INT BIT(20) +#define GHWCFG2_DYNAMIC_FIFO BIT(19) +#define GHWCFG2_PERIO_EP_SUPPORTED BIT(18) +#define GHWCFG2_NUM_HOST_CHAN_MASK GENMASK(17, 14) +#define GHWCFG2_NUM_DEV_EP_MASK GENMASK(13, 10) +#define GHWCFG2_FS_PHY_TYPE_MASK GENMASK(9, 8) +#define GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED 0 +#define GHWCFG2_FS_PHY_TYPE_DEDICATED 1 +#define GHWCFG2_FS_PHY_TYPE_SHARED_UTMI 2 +#define GHWCFG2_FS_PHY_TYPE_SHARED_ULPI 3 +#define GHWCFG2_HS_PHY_TYPE_MASK GENMASK(7, 6) +#define GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0 +#define GHWCFG2_HS_PHY_TYPE_UTMI 1 +#define GHWCFG2_HS_PHY_TYPE_ULPI 2 +#define GHWCFG2_HS_PHY_TYPE_UTMI_ULPI 3 +#define GHWCFG2_POINT2POINT BIT(5) +#define GHWCFG2_ARCHITECTURE_MASK GENMASK(4, 3) +#define GHWCFG2_SLAVE_ONLY_ARCH 0 +#define GHWCFG2_EXT_DMA_ARCH 1 +#define GHWCFG2_INT_DMA_ARCH 2 +#define GHWCFG2_OP_MODE_MASK GENMASK(2, 0) +#define GHWCFG2_OP_MODE_HNP_SRP_CAPABLE 0 +#define GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE 1 +#define GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE 2 +#define GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3 +#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4 +#define GHWCFG2_OP_MODE_SRP_CAPABLE_HOST 5 +#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6 +#define GHWCFG2_OP_MODE_UNDEFINED 7 + +#define GHWCFG4_DESC_DMA_DYN BIT(31) +#define GHWCFG4_DESC_DMA BIT(30) +#define GHWCFG4_NUM_IN_EPS_MASK GENMASK(29, 26) +#define GHWCFG4_DED_FIFO_EN BIT(25) +#define GHWCFG4_SESSION_END_FILT_EN BIT(24) +#define GHWCFG4_B_VALID_FILT_EN BIT(23) +#define GHWCFG4_A_VALID_FILT_EN BIT(22) +#define GHWCFG4_VBUS_VALID_FILT_EN BIT(21) +#define GHWCFG4_IDDIG_FILT_EN BIT(20) +#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_MASK GENMASK(19, 16) +#define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK GENMASK(15, 14) +#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0 +#define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1 +#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2 +#define GHWCFG4_ACG_SUPPORTED BIT(12) +#define GHWCFG4_IPG_ISOC_SUPPORTED BIT(11) +#define GHWCFG4_SERVICE_INTERVAL_SUPPORTED BIT(10) +#define GHWCFG4_XHIBER BIT(7) +#define GHWCFG4_HIBER BIT(6) +#define GHWCFG4_MIN_AHB_FREQ BIT(5) +#define GHWCFG4_POWER_OPTIMIZ BIT(4) +#define GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK GENMASK(3, 0) + +#define FIFOSIZE_DEPTH_MASK GENMASK(31, 16) +#define FIFOSIZE_STARTADDR_MASK GENMASK(15, 0) + +/* Host Register */ +#define HCFG_MODECHTIMEN BIT(31) +#define HCFG_PERSCHEDENA BIT(26) +#define HCFG_FRLISTEN_MASK GENMASK(25, 24) +#define HCFG_FRLISTEN_8 0 +#define HCFG_FRLISTEN_16 1 +#define HCFG_FRLISTEN_32 2 +#define HCFG_FRLISTEN_64 3 +#define HCFG_DESCDMA BIT(23) +#define HCFG_RESVALID_MASK GENMASK(15, 8) +#define HCFG_ENA32KHZ BIT(7) +#define HCFG_FSLSSUPP BIT(2) +#define HCFG_FSLSPCLKSEL_MASK GENMASK(2, 0) +#define HCFG_FSLSPCLKSEL_30_60_MHZ 0 +#define HCFG_FSLSPCLKSEL_48_MHZ 1 +#define HCFG_FSLSPCLKSEL_6_MHZ 2 + +#define HFNUM_FRREM_MASK GENMASK(31, 16) +#define HFNUM_FRNUM_MASK GENMASK(15, 0) + +#define HPRT0_SPD_MASK GENMASK(18, 17) +#define HPRT0_SPD_HIGH_SPEED 0 +#define HPRT0_SPD_FULL_SPEED 1 +#define HPRT0_SPD_LOW_SPEED 2 +#define HPRT0_TSTCTL_MASK GENMASK(16, 13) +#define HPRT0_PWR BIT(12) +#define HPRT0_LNSTS_MASK GENMASK(11, 10) +#define HPRT0_RST BIT(8) +#define HPRT0_SUSP BIT(7) +#define HPRT0_RES BIT(6) +#define HPRT0_OVRCURRCHG BIT(5) +#define HPRT0_OVRCURRACT BIT(4) +#define HPRT0_ENACHG BIT(3) +#define HPRT0_ENA BIT(2) +#define HPRT0_CONNDET BIT(1) +#define HPRT0_CONNSTS BIT(0) +#define HPRT0_W1C_MASK (HPRT0_CONNDET | \ + HPRT0_ENA | \ + HPRT0_ENACHG | \ + HPRT0_OVRCURRCHG) + +#define HCCHAR_CHENA BIT(31) +#define HCCHAR_CHDIS BIT(30) +#define HCCHAR_ODDFRM BIT(29) +#define HCCHAR_DEVADDR_MASK GENMASK(28, 22) +#define HCCHAR_MULTICNT_MASK GENMASK(21, 20) +#define HCCHAR_EPTYPE_MASK GENMASK(19, 18) +#define HCCHAR_EPTYPE_CONTROL 0 +#define HCCHAR_EPTYPE_ISOC 1 +#define HCCHAR_EPTYPE_BULK 2 +#define HCCHAR_EPTYPE_INTR 3 +#define HCCHAR_LSPDDEV BIT(17) +#define HCCHAR_EPDIR BIT(15) +#define HCCHAR_EPNUM_MASK GENMASK(14, 11) +#define HCCHAR_MPS_MASK GENMASK(10, 0) + +#define HCSPLT_SPLTENA BIT(31) +#define HCSPLT_COMPSPLT BIT(16) +#define HCSPLT_XACTPOS_MASK GENMASK(15, 14) +#define HCSPLT_XACTPOS_MID 0 +#define HCSPLT_XACTPOS_END 1 +#define HCSPLT_XACTPOS_BEGIN 2 +#define HCSPLT_XACTPOS_ALL 3 +#define HCSPLT_HUBADDR_MASK GENMASK(13, 7) +#define HCSPLT_PRTADDR_MASK GENMASK(6, 0) + +#define HCINTMSK_FRM_LIST_ROLL BIT(13) +#define HCINTMSK_XCS_XACT BIT(12) +#define HCINTMSK_BNA BIT(11) +#define HCINTMSK_DATATGLERR BIT(10) +#define HCINTMSK_FRMOVRUN BIT(9) +#define HCINTMSK_BBLERR BIT(8) +#define HCINTMSK_XACTERR BIT(7) +#define HCINTMSK_NYET BIT(6) +#define HCINTMSK_ACK BIT(5) +#define HCINTMSK_NAK BIT(4) +#define HCINTMSK_STALL BIT(3) +#define HCINTMSK_AHBERR BIT(2) +#define HCINTMSK_CHHLTD BIT(1) +#define HCINTMSK_XFERCOMPL BIT(0) + +#define TSIZ_DOPNG BIT(31) +#define TSIZ_SC_MC_PID_MASK GENMASK(30, 29) +#define TSIZ_SC_MC_PID_DATA0 0 +#define TSIZ_SC_MC_PID_DATA2 1 +#define TSIZ_SC_MC_PID_DATA1 2 +#define TSIZ_SC_MC_PID_MDATA 3 +#define TSIZ_SC_MC_PID_SETUP 3 +#define TSIZ_PKTCNT_MASK GENMASK(28, 19) +#define TSIZ_NTD_MASK GENMASK(15, 8) +#define TSIZ_SCHINFO_MASK GENMASK(7, 0) +#define TSIZ_XFERSIZE_MASK GENMASK(18, 0) + +/* Device Mode Register */ +#define DCFG_DESCDMA_EN BIT(23) +#define DCFG_EPMISCNT_MASK GENMASK(22, 18) +#define DCFG_IPG_ISOC_SUPPORDED BIT(17) +#define DCFG_PERFRINT_MASK GENMASK(12, 11) +#define DCFG_DEVADDR_MASK GENMASK(10, 4) +#define DCFG_NZ_STS_OUT_HSHK BIT(2) +#define DCFG_DEVSPD_MASK GENMASK(1, 0) +#define DCFG_DEVSPD_HS 0 +#define DCFG_DEVSPD_FS 1 +#define DCFG_DEVSPD_LS 2 +#define DCFG_DEVSPD_FS48 3 + +#define DCTL_SERVICE_INTERVAL_SUPPORTED BIT(19) +#define DCTL_PWRONPRGDONE BIT(11) +#define DCTL_CGOUTNAK BIT(10) +#define DCTL_SGOUTNAK BIT(9) +#define DCTL_CGNPINNAK BIT(8) +#define DCTL_SGNPINNAK BIT(7) +#define DCTL_TSTCTL_MASK GENMASK(6, 4) +#define DCTL_GOUTNAKSTS BIT(3) +#define DCTL_GNPINNAKSTS BIT(2) +#define DCTL_SFTDISCON BIT(1) +#define DCTL_RMTWKUPSIG BIT(0) + +#define DSTS_SOFFN_MASK GENMASK(21, 8) +#define DSTS_ERRATICERR BIT(3) +#define DSTS_ENUMSPD_MASK GENMASK(2, 1) +#define DSTS_ENUMSPD_HS 0 +#define DSTS_ENUMSPD_FS 1 +#define DSTS_ENUMSPD_LS 2 +#define DSTS_ENUMSPD_FS48 3 +#define DSTS_SUSPSTS BIT(0) + +#define DIEPMSK_NAKMSK BIT(13) +#define DIEPMSK_BNAININTRMSK BIT(9) +#define DIEPMSK_TXFIFOUNDRNMSK BIT(8) +#define DIEPMSK_TXFIFOEMPTY BIT(7) +#define DIEPMSK_INEPNAKEFFMSK BIT(6) +#define DIEPMSK_INTKNEPMISMSK BIT(5) +#define DIEPMSK_INTKNTXFEMPMSK BIT(4) +#define DIEPMSK_TIMEOUTMSK BIT(3) +#define DIEPMSK_AHBERRMSK BIT(2) +#define DIEPMSK_EPDISBLDMSK BIT(1) +#define DIEPMSK_XFERCOMPLMSK BIT(0) + +#define DOEPMSK_BNAMSK BIT(9) +#define DOEPMSK_BACK2BACKSETUP BIT(6) +#define DOEPMSK_STSPHSERCVDMSK BIT(5) +#define DOEPMSK_OUTTKNEPDISMSK BIT(4) +#define DOEPMSK_SETUPMSK BIT(3) +#define DOEPMSK_AHBERRMSK BIT(2) +#define DOEPMSK_EPDISBLDMSK BIT(1) +#define DOEPMSK_XFERCOMPLMSK BIT(0) + +#define DAINT_OUTEP_MASK GENMASK(31, 16) +#define DAINT_INEP_MASK GENMASK(15, 0) + +#define D0EPCTL_MPS_MASK GENMASK(1, 0) +#define D0EPCTL_MPS_64 0 +#define D0EPCTL_MPS_32 1 +#define D0EPCTL_MPS_16 2 +#define D0EPCTL_MPS_8 3 + +#define DXEPCTL_EPENA BIT(31) +#define DXEPCTL_EPDIS BIT(30) +#define DXEPCTL_SETD1PID BIT(29) +#define DXEPCTL_SETODDFR BIT(29) +#define DXEPCTL_SETD0PID BIT(28) +#define DXEPCTL_SETEVENFR BIT(28) +#define DXEPCTL_SNAK BIT(27) +#define DXEPCTL_CNAK BIT(26) +#define DXEPCTL_TXFNUM_MASK GENMASK(25, 22) +#define DXEPCTL_STALL BIT(21) +#define DXEPCTL_SNP BIT(20) +#define DXEPCTL_EPTYPE_MASK GENMASK(19, 18) +#define DXEPCTL_EPTYPE_CONTROL 0 +#define DXEPCTL_EPTYPE_ISO 1 +#define DXEPCTL_EPTYPE_BULK 2 +#define DXEPCTL_EPTYPE_INTERRUPT 3 +#define DXEPCTL_NAKSTS BIT(17) +#define DXEPCTL_DPID BIT(16) +#define DXEPCTL_EOFRNUM BIT(16) +#define DXEPCTL_USBACTEP BIT(15) +#define DXEPCTL_NEXTEP_MASK GENMASK(14, 11) +#define DXEPCTL_MPS_MASK GENMASK(10, 0) + +#define DXEPINT_SETUP_RCVD BIT(15) +#define DXEPINT_NYETINTRPT BIT(14) +#define DXEPINT_NAKINTRPT BIT(13) +#define DXEPINT_BBLEERRINTRPT BIT(12) +#define DXEPINT_PKTDRPSTS BIT(11) +#define DXEPINT_BNAINTR BIT(9) +#define DXEPINT_TXFIFOUNDRN BIT(8) +#define DXEPINT_OUTPKTERR BIT(8) +#define DXEPINT_TXFEMP BIT(7) +#define DXEPINT_INEPNAKEFF BIT(6) +#define DXEPINT_BACK2BACKSETUP BIT(6) +#define DXEPINT_INTKNEPMIS BIT(5) +#define DXEPINT_STSPHSERCVD BIT(5) +#define DXEPINT_INTKNTXFEMP BIT(4) +#define DXEPINT_OUTTKNEPDIS BIT(4) +#define DXEPINT_TIMEOUT BIT(3) +#define DXEPINT_SETUP BIT(3) +#define DXEPINT_AHBERR BIT(2) +#define DXEPINT_EPDISBLD BIT(1) +#define DXEPINT_XFERCOMPL BIT(0) + +#define DIEPTSIZ0_PKTCNT_MASK GENMASK(20, 19) +#define DIEPTSIZ0_XFERSIZE_MASK GENMASK(6, 0) + +#define DOEPTSIZ0_SUPCNT_MASK GENMASK(30, 29) +#define DOEPTSIZ0_PKTCNT BIT(19) +#define DOEPTSIZ0_XFERSIZE_MASK GENMASK(6, 0) + +#define DXEPTSIZ_MC_MASK GENMASK(30, 29) +#define DXEPTSIZ_PKTCNT_MASK GENMASK(28, 19) +#define DXEPTSIZ_XFERSIZE_MASK GENMASK(18, 0) + +#endif /* __DWC2_CORE_H_ */ 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/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index 7e9dd6f4268..40393141ca9 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -29,6 +29,7 @@ #include <linux/delay.h> #include <linux/printk.h> +#include <linux/bitfield.h> #include <linux/errno.h> #include <linux/list.h> @@ -45,6 +46,7 @@ #include <power/regulator.h> +#include "../common/dwc2_core.h" #include "dwc2_udc_otg_regs.h" #include "dwc2_udc_otg_priv.h" @@ -154,11 +156,11 @@ static struct usb_ep_ops dwc2_ep_ops = { /***********************************************************/ -struct dwc2_usbotg_reg *reg; +struct dwc2_core_regs *reg; bool dfu_usb_get_reset(void) { - return !!(readl(®->gintsts) & INT_RESET); + return !!(readl(®->global_regs.gintsts) & GINTSTS_USBRST); } __weak void otg_phy_init(struct dwc2_udc *dev) {} @@ -229,7 +231,7 @@ static int udc_enable(struct dwc2_udc *dev) debug_cond(DEBUG_SETUP != 0, "DWC2 USB 2.0 OTG Controller Core Initialized : 0x%x\n", - readl(®->gintmsk)); + readl(®->global_regs.gintmsk)); dev->gadget.speed = USB_SPEED_UNKNOWN; @@ -238,8 +240,8 @@ static int udc_enable(struct dwc2_udc *dev) static int dwc2_gadget_pullup(struct usb_gadget *g, int is_on) { - clrsetbits_le32(®->dctl, SOFT_DISCONNECT, - is_on ? 0 : SOFT_DISCONNECT); + clrsetbits_le32(®->device_regs.dctl, DCTL_SFTDISCON, + is_on ? 0 : DCTL_SFTDISCON); return 0; } @@ -463,12 +465,13 @@ static void reconfig_usbd(struct dwc2_udc *dev) { /* 2. Soft-reset OTG Core and then unreset again. */ int i; - unsigned int uTemp = writel(CORE_SOFT_RESET, ®->grstctl); - uint32_t dflt_gusbcfg; - uint32_t rx_fifo_sz, tx_fifo_sz, np_tx_fifo_sz; + u32 dflt_gusbcfg; + u32 rx_fifo_sz, tx_fifo_sz, np_tx_fifo_sz; u32 max_hw_ep; int pdata_hw_ep; + dwc2_core_reset(reg); + debug("Resetting OTG controller\n"); dflt_gusbcfg = @@ -490,47 +493,44 @@ static void reconfig_usbd(struct dwc2_udc *dev) if (dev->pdata->usb_gusbcfg) dflt_gusbcfg = dev->pdata->usb_gusbcfg; - writel(dflt_gusbcfg, ®->gusbcfg); + writel(dflt_gusbcfg, ®->global_regs.gusbcfg); /* 3. Put the OTG device core in the disconnected state.*/ - uTemp = readl(®->dctl); - uTemp |= SOFT_DISCONNECT; - writel(uTemp, ®->dctl); + setbits_le32(®->device_regs.dctl, DCTL_SFTDISCON); udelay(20); /* 4. Make the OTG device core exit from the disconnected state.*/ - uTemp = readl(®->dctl); - uTemp = uTemp & ~SOFT_DISCONNECT; - writel(uTemp, ®->dctl); + clrbits_le32(®->device_regs.dctl, DCTL_SFTDISCON); /* 5. Configure OTG Core to initial settings of device mode.*/ /* [][1: full speed(30Mhz) 0:high speed]*/ - writel(EP_MISS_CNT(1) | DEV_SPEED_HIGH_SPEED_20, ®->dcfg); + writel(FIELD_PREP(DCFG_EPMISCNT_MASK, 1) | + FIELD_PREP(DCFG_DEVSPD_MASK, DCFG_DEVSPD_HS), ®->device_regs.dcfg); mdelay(1); /* 6. Unmask the core interrupts*/ - writel(GINTMSK_INIT, ®->gintmsk); + writel(GINTMSK_INIT, ®->global_regs.gintmsk); /* 7. Set NAK bit of EP0, EP1, EP2*/ - writel(DEPCTL_EPDIS|DEPCTL_SNAK, ®->out_endp[EP0_CON].doepctl); - writel(DEPCTL_EPDIS|DEPCTL_SNAK, ®->in_endp[EP0_CON].diepctl); + writel(DXEPCTL_EPDIS | DXEPCTL_SNAK, ®->device_regs.out_endp[EP0_CON].doepctl); + writel(DXEPCTL_EPDIS | DXEPCTL_SNAK, ®->device_regs.in_endp[EP0_CON].diepctl); for (i = 1; i < DWC2_MAX_ENDPOINTS; i++) { - writel(DEPCTL_EPDIS|DEPCTL_SNAK, ®->out_endp[i].doepctl); - writel(DEPCTL_EPDIS|DEPCTL_SNAK, ®->in_endp[i].diepctl); + writel(DXEPCTL_EPDIS | DXEPCTL_SNAK, ®->device_regs.out_endp[i].doepctl); + writel(DXEPCTL_EPDIS | DXEPCTL_SNAK, ®->device_regs.in_endp[i].diepctl); } /* 8. Unmask EPO interrupts*/ - writel(((1 << EP0_CON) << DAINT_OUT_BIT) - | (1 << EP0_CON), ®->daintmsk); + writel(FIELD_PREP(DAINT_OUTEP_MASK, BIT(EP0_CON)) | + FIELD_PREP(DAINT_INEP_MASK, BIT(EP0_CON)), ®->device_regs.daintmsk); /* 9. Unmask device OUT EP common interrupts*/ - writel(DOEPMSK_INIT, ®->doepmsk); + writel(DOEPMSK_INIT, ®->device_regs.doepmsk); /* 10. Unmask device IN EP common interrupts*/ - writel(DIEPMSK_INIT, ®->diepmsk); + writel(DIEPMSK_INIT, ®->device_regs.diepmsk); rx_fifo_sz = RX_FIFO_SIZE; np_tx_fifo_sz = NPTX_FIFO_SIZE; @@ -544,15 +544,15 @@ static void reconfig_usbd(struct dwc2_udc *dev) tx_fifo_sz = dev->pdata->tx_fifo_sz; /* 11. Set Rx FIFO Size (in 32-bit words) */ - writel(rx_fifo_sz, ®->grxfsiz); + writel(rx_fifo_sz, ®->global_regs.grxfsiz); /* 12. Set Non Periodic Tx FIFO Size */ - writel((np_tx_fifo_sz << 16) | rx_fifo_sz, - ®->gnptxfsiz); + writel(FIELD_PREP(FIFOSIZE_DEPTH_MASK, np_tx_fifo_sz) | + FIELD_PREP(FIFOSIZE_STARTADDR_MASK, rx_fifo_sz), + ®->global_regs.gnptxfsiz); /* retrieve the number of IN Endpoints (excluding ep0) */ - max_hw_ep = (readl(®->ghwcfg4) & GHWCFG4_NUM_IN_EPS_MASK) >> - GHWCFG4_NUM_IN_EPS_SHIFT; + max_hw_ep = FIELD_GET(GHWCFG4_NUM_IN_EPS_MASK, readl(®->global_regs.ghwcfg4)); pdata_hw_ep = dev->pdata->tx_fifo_sz_nb; /* tx_fifo_sz_nb should equal to number of IN Endpoint */ @@ -564,33 +564,29 @@ static void reconfig_usbd(struct dwc2_udc *dev) if (pdata_hw_ep) tx_fifo_sz = dev->pdata->tx_fifo_sz_array[i]; - writel((rx_fifo_sz + np_tx_fifo_sz + (tx_fifo_sz * i)) | - tx_fifo_sz << 16, ®->dieptxf[i]); + writel(FIELD_PREP(FIFOSIZE_DEPTH_MASK, tx_fifo_sz) | + FIELD_PREP(FIFOSIZE_STARTADDR_MASK, + rx_fifo_sz + np_tx_fifo_sz + tx_fifo_sz * i), + ®->global_regs.dptxfsizn[i]); } /* Flush the RX FIFO */ - writel(RX_FIFO_FLUSH, ®->grstctl); - while (readl(®->grstctl) & RX_FIFO_FLUSH) - debug("%s: waiting for DWC2_UDC_OTG_GRSTCTL\n", __func__); + dwc2_flush_rx_fifo(reg); /* Flush all the Tx FIFO's */ - writel(TX_FIFO_FLUSH_ALL, ®->grstctl); - writel(TX_FIFO_FLUSH_ALL | TX_FIFO_FLUSH, ®->grstctl); - while (readl(®->grstctl) & TX_FIFO_FLUSH) - debug("%s: waiting for DWC2_UDC_OTG_GRSTCTL\n", __func__); + dwc2_flush_tx_fifo(reg, GRSTCTL_TXFNUM_ALL); /* 13. Clear NAK bit of EP0, EP1, EP2*/ /* For Slave mode*/ /* EP0: Control OUT */ - writel(DEPCTL_EPDIS | DEPCTL_CNAK, - ®->out_endp[EP0_CON].doepctl); + writel(DXEPCTL_EPDIS | DXEPCTL_CNAK, + ®->device_regs.out_endp[EP0_CON].doepctl); /* 14. Initialize OTG Link Core.*/ - writel(GAHBCFG_INIT, ®->gahbcfg); + writel(GAHBCFG_INIT, ®->global_regs.gahbcfg); } static void set_max_pktsize(struct dwc2_udc *dev, enum usb_device_speed speed) { - unsigned int ep_ctrl; int i; if (speed == USB_SPEED_HIGH) { @@ -610,12 +606,10 @@ static void set_max_pktsize(struct dwc2_udc *dev, enum usb_device_speed speed) dev->ep[i].ep.maxpacket = ep_fifo_size; /* EP0 - Control IN (64 bytes)*/ - ep_ctrl = readl(®->in_endp[EP0_CON].diepctl); - writel(ep_ctrl|(0<<0), ®->in_endp[EP0_CON].diepctl); + setbits_le32(®->device_regs.in_endp[EP0_CON].diepctl, (0 << 0)); /* EP0 - Control OUT (64 bytes)*/ - ep_ctrl = readl(®->out_endp[EP0_CON].doepctl); - writel(ep_ctrl|(0<<0), ®->out_endp[EP0_CON].doepctl); + setbits_le32(®->device_regs.out_endp[EP0_CON].doepctl, (0 << 0)); } static int dwc2_ep_enable(struct usb_ep *_ep, @@ -904,7 +898,7 @@ int dwc2_udc_probe(struct dwc2_plat_otg_data *pdata) dev->pdata = pdata; - reg = (struct dwc2_usbotg_reg *)pdata->regs_otg; + reg = (struct dwc2_core_regs *)pdata->regs_otg; dev->gadget.is_dualspeed = 1; /* Hack only*/ dev->gadget.is_otg = 0; @@ -932,8 +926,8 @@ int dwc2_udc_probe(struct dwc2_plat_otg_data *pdata) int dwc2_udc_handle_interrupt(void) { - u32 intr_status = readl(®->gintsts); - u32 gintmsk = readl(®->gintmsk); + u32 intr_status = readl(®->global_regs.gintsts); + u32 gintmsk = readl(®->global_regs.gintmsk); if (intr_status & gintmsk) return dwc2_udc_irq(1, (void *)the_controller); @@ -1087,8 +1081,8 @@ static int dwc2_udc_otg_probe(struct udevice *dev) { struct dwc2_plat_otg_data *plat = dev_get_plat(dev); struct dwc2_priv_data *priv = dev_get_priv(dev); - struct dwc2_usbotg_reg *usbotg_reg = - (struct dwc2_usbotg_reg *)plat->regs_otg; + struct dwc2_core_regs *usbotg_reg = + (struct dwc2_core_regs *)plat->regs_otg; int ret; ret = dwc2_udc_otg_clk_init(dev, &priv->clks); @@ -1123,21 +1117,22 @@ static int dwc2_udc_otg_probe(struct udevice *dev) if (plat->force_b_session_valid && !plat->force_vbus_detection) { /* Override VBUS detection: enable then value*/ - setbits_le32(&usbotg_reg->gotgctl, VB_VALOEN); - setbits_le32(&usbotg_reg->gotgctl, VB_VALOVAL); + setbits_le32(&usbotg_reg->global_regs.gotgctl, GOTGCTL_VBVALOEN); + setbits_le32(&usbotg_reg->global_regs.gotgctl, GOTGCTL_VBVALOVAL); } else { /* Enable VBUS sensing */ - setbits_le32(&usbotg_reg->ggpio, + setbits_le32(&usbotg_reg->global_regs.ggpio, GGPIO_STM32_OTG_GCCFG_VBDEN); } if (plat->force_b_session_valid) { /* Override B session bits: enable then value */ - setbits_le32(&usbotg_reg->gotgctl, A_VALOEN | B_VALOEN); - setbits_le32(&usbotg_reg->gotgctl, - A_VALOVAL | B_VALOVAL); + setbits_le32(&usbotg_reg->global_regs.gotgctl, + GOTGCTL_AVALOEN | GOTGCTL_BVALOEN); + setbits_le32(&usbotg_reg->global_regs.gotgctl, + GOTGCTL_AVALOVAL | GOTGCTL_BVALOVAL); } else { /* Enable ID detection */ - setbits_le32(&usbotg_reg->ggpio, + setbits_le32(&usbotg_reg->global_regs.ggpio, GGPIO_STM32_OTG_GCCFG_IDEN); } } @@ -1200,10 +1195,10 @@ U_BOOT_DRIVER(dwc2_udc_otg) = { int dwc2_udc_B_session_valid(struct udevice *dev) { struct dwc2_plat_otg_data *plat = dev_get_plat(dev); - struct dwc2_usbotg_reg *usbotg_reg = - (struct dwc2_usbotg_reg *)plat->regs_otg; + struct dwc2_core_regs *usbotg_reg = + (struct dwc2_core_regs *)plat->regs_otg; - return readl(&usbotg_reg->gotgctl) & B_SESSION_VALID; + return readl(&usbotg_reg->global_regs.gotgctl) & GOTGCTL_BSESVLD; } #else int dm_usb_gadget_handle_interrupts(struct udevice *dev) diff --git a/drivers/usb/gadget/dwc2_udc_otg_phy.c b/drivers/usb/gadget/dwc2_udc_otg_phy.c index c7eea7b3442..e0ac5d142b0 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_phy.c +++ b/drivers/usb/gadget/dwc2_udc_otg_phy.c @@ -48,29 +48,24 @@ void otg_phy_init(struct dwc2_udc *dev) printf("USB PHY0 Enable\n"); /* Enable PHY */ - writel(readl(usb_phy_ctrl) | USB_PHY_CTRL_EN0, usb_phy_ctrl); + setbits_le32(usb_phy_ctrl, USB_PHY_CTRL_EN0); if (dev->pdata->usb_flags == PHY0_SLEEP) /* C210 Universal */ - writel((readl(&phy->phypwr) - &~(PHY_0_SLEEP | OTG_DISABLE_0 | ANALOG_PWRDOWN) - &~FORCE_SUSPEND_0), &phy->phypwr); + clrbits_le32(&phy->phypwr, PHY_0_SLEEP | OTG_DISABLE_0 | + ANALOG_PWRDOWN | FORCE_SUSPEND_0); else /* C110 GONI */ - writel((readl(&phy->phypwr) &~(OTG_DISABLE_0 | ANALOG_PWRDOWN) - &~FORCE_SUSPEND_0), &phy->phypwr); + clrbits_le32(&phy->phypwr, OTG_DISABLE_0 | ANALOG_PWRDOWN | FORCE_SUSPEND_0); if (s5p_cpu_id == 0x4412) - writel((readl(&phy->phyclk) & ~(EXYNOS4X12_ID_PULLUP0 | - EXYNOS4X12_COMMON_ON_N0)) | EXYNOS4X12_CLK_SEL_24MHZ, - &phy->phyclk); /* PLL 24Mhz */ + clrsetbits_le32(&phy->phyclk, EXYNOS4X12_ID_PULLUP0 | EXYNOS4X12_COMMON_ON_N0, + EXYNOS4X12_CLK_SEL_24MHZ); /* PLL 24Mhz */ else - writel((readl(&phy->phyclk) & ~(ID_PULLUP0 | COMMON_ON_N0)) | - CLK_SEL_24MHZ, &phy->phyclk); /* PLL 24Mhz */ + clrsetbits_le32(&phy->phyclk, ID_PULLUP0 | COMMON_ON_N0, + CLK_SEL_24MHZ); /* PLL 24Mhz */ - writel((readl(&phy->rstcon) &~(LINK_SW_RST | PHYLNK_SW_RST)) - | PHY_SW_RST0, &phy->rstcon); + clrsetbits_le32(&phy->rstcon, LINK_SW_RST | PHYLNK_SW_RST, PHY_SW_RST0); udelay(10); - writel(readl(&phy->rstcon) - &~(PHY_SW_RST0 | LINK_SW_RST | PHYLNK_SW_RST), &phy->rstcon); + clrbits_le32(&phy->rstcon, PHY_SW_RST0 | LINK_SW_RST | PHYLNK_SW_RST); udelay(10); } @@ -86,13 +81,11 @@ void otg_phy_off(struct dwc2_udc *dev) writel(readl(&phy->phypwr) &~PHY_SW_RST0, &phy->rstcon); udelay(20); - writel(readl(&phy->phypwr) | OTG_DISABLE_0 | ANALOG_PWRDOWN - | FORCE_SUSPEND_0, &phy->phypwr); + setbits_le32(&phy->phypwr, OTG_DISABLE_0 | ANALOG_PWRDOWN | FORCE_SUSPEND_0); - writel(readl(usb_phy_ctrl) &~USB_PHY_CTRL_EN0, usb_phy_ctrl); + clrbits_le32(usb_phy_ctrl, USB_PHY_CTRL_EN0); - writel((readl(&phy->phyclk) & ~(ID_PULLUP0 | COMMON_ON_N0)), - &phy->phyclk); + clrbits_le32(&phy->phyclk, ID_PULLUP0 | COMMON_ON_N0); udelay(10000); diff --git a/drivers/usb/gadget/dwc2_udc_otg_regs.h b/drivers/usb/gadget/dwc2_udc_otg_regs.h index 01056fab1c2..5dd2d3a45bf 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_regs.h +++ b/drivers/usb/gadget/dwc2_udc_otg_regs.h @@ -10,286 +10,59 @@ #ifndef __ASM_ARCH_REGS_USB_OTG_HS_H #define __ASM_ARCH_REGS_USB_OTG_HS_H -/* USB2.0 OTG Controller register */ -#include <linux/bitops.h> +#include "../common/dwc2_core.h" + struct dwc2_usbotg_phy { u32 phypwr; u32 phyclk; u32 rstcon; }; -/* Device Logical IN Endpoint-Specific Registers */ -struct dwc2_dev_in_endp { - u32 diepctl; - u8 res1[4]; - u32 diepint; - u8 res2[4]; - u32 dieptsiz; - u32 diepdma; - u8 res3[4]; - u32 diepdmab; -}; - -/* Device Logical OUT Endpoint-Specific Registers */ -struct dwc2_dev_out_endp { - u32 doepctl; - u8 res1[4]; - u32 doepint; - u8 res2[4]; - u32 doeptsiz; - u32 doepdma; - u8 res3[4]; - u32 doepdmab; -}; - -struct ep_fifo { - u32 fifo; - u8 res[4092]; -}; - -/* USB2.0 OTG Controller register */ -struct dwc2_usbotg_reg { - /* Core Global Registers */ - u32 gotgctl; /* OTG Control & Status */ - u32 gotgint; /* OTG Interrupt */ - u32 gahbcfg; /* Core AHB Configuration */ - u32 gusbcfg; /* Core USB Configuration */ - u32 grstctl; /* Core Reset */ - u32 gintsts; /* Core Interrupt */ - u32 gintmsk; /* Core Interrupt Mask */ - u32 grxstsr; /* Receive Status Debug Read/Status Read */ - u32 grxstsp; /* Receive Status Debug Pop/Status Pop */ - u32 grxfsiz; /* Receive FIFO Size */ - u32 gnptxfsiz; /* Non-Periodic Transmit FIFO Size */ - u8 res0[12]; - u32 ggpio; /* 0x038 */ - u8 res1[20]; - u32 ghwcfg4; /* User HW Config4 */ - u8 res2[176]; - u32 dieptxf[15]; /* Device Periodic Transmit FIFO size register */ - u8 res3[1728]; - /* Device Configuration */ - u32 dcfg; /* Device Configuration Register */ - u32 dctl; /* Device Control */ - u32 dsts; /* Device Status */ - u8 res4[4]; - u32 diepmsk; /* Device IN Endpoint Common Interrupt Mask */ - u32 doepmsk; /* Device OUT Endpoint Common Interrupt Mask */ - u32 daint; /* Device All Endpoints Interrupt */ - u32 daintmsk; /* Device All Endpoints Interrupt Mask */ - u8 res5[224]; - struct dwc2_dev_in_endp in_endp[16]; - struct dwc2_dev_out_endp out_endp[16]; - u8 res6[768]; - struct ep_fifo ep[16]; -}; - -/*===================================================================== */ -/*definitions related to CSR setting */ - -/* DWC2_UDC_OTG_GOTGCTL */ -#define B_SESSION_VALID BIT(19) -#define A_SESSION_VALID BIT(18) -#define B_VALOVAL BIT(7) -#define B_VALOEN BIT(6) -#define A_VALOVAL BIT(5) -#define A_VALOEN BIT(4) -#define VB_VALOVAL BIT(3) -#define VB_VALOEN BIT(2) - -/* DWC2_UDC_OTG_GOTINT */ -#define GOTGINT_SES_END_DET (1<<2) - -/* DWC2_UDC_OTG_GAHBCFG */ -#define PTXFE_HALF (0<<8) -#define PTXFE_ZERO (1<<8) -#define NPTXFE_HALF (0<<7) -#define NPTXFE_ZERO (1<<7) -#define MODE_SLAVE (0<<5) -#define MODE_DMA (1<<5) -#define BURST_SINGLE (0<<1) -#define BURST_INCR (1<<1) -#define BURST_INCR4 (3<<1) -#define BURST_INCR8 (5<<1) -#define BURST_INCR16 (7<<1) -#define GBL_INT_UNMASK (1<<0) -#define GBL_INT_MASK (0<<0) - -/* DWC2_UDC_OTG_GRSTCTL */ -#define AHB_MASTER_IDLE (1u<<31) -#define CORE_SOFT_RESET (0x1<<0) - -/* DWC2_UDC_OTG_GINTSTS/DWC2_UDC_OTG_GINTMSK core interrupt register */ -#define INT_RESUME (1u<<31) -#define INT_DISCONN (0x1<<29) -#define INT_CONN_ID_STS_CNG (0x1<<28) -#define INT_OUT_EP (0x1<<19) -#define INT_IN_EP (0x1<<18) -#define INT_ENUMDONE (0x1<<13) -#define INT_RESET (0x1<<12) -#define INT_SUSPEND (0x1<<11) -#define INT_EARLY_SUSPEND (0x1<<10) -#define INT_NP_TX_FIFO_EMPTY (0x1<<5) -#define INT_RX_FIFO_NOT_EMPTY (0x1<<4) -#define INT_SOF (0x1<<3) -#define INT_OTG (0x1<<2) -#define INT_DEV_MODE (0x0<<0) -#define INT_HOST_MODE (0x1<<1) -#define INT_GOUTNakEff (0x01<<7) -#define INT_GINNakEff (0x01<<6) - #define FULL_SPEED_CONTROL_PKT_SIZE 8 #define FULL_SPEED_BULK_PKT_SIZE 64 #define HIGH_SPEED_CONTROL_PKT_SIZE 64 #define HIGH_SPEED_BULK_PKT_SIZE 512 -#define RX_FIFO_SIZE (1024) -#define NPTX_FIFO_SIZE (1024) -#define PTX_FIFO_SIZE (384) - -#define DEPCTL_TXFNUM_0 (0x0<<22) -#define DEPCTL_TXFNUM_1 (0x1<<22) -#define DEPCTL_TXFNUM_2 (0x2<<22) -#define DEPCTL_TXFNUM_3 (0x3<<22) -#define DEPCTL_TXFNUM_4 (0x4<<22) - -/* Enumeration speed */ -#define USB_HIGH_30_60MHZ (0x0<<1) -#define USB_FULL_30_60MHZ (0x1<<1) -#define USB_LOW_6MHZ (0x2<<1) -#define USB_FULL_48MHZ (0x3<<1) +#define RX_FIFO_SIZE 1024 +#define NPTX_FIFO_SIZE 1024 +#define PTX_FIFO_SIZE 384 -/* DWC2_UDC_OTG_GRXSTSP STATUS */ -#define OUT_PKT_RECEIVED (0x2<<17) -#define OUT_TRANSFER_COMPLELTED (0x3<<17) -#define SETUP_TRANSACTION_COMPLETED (0x4<<17) -#define SETUP_PKT_RECEIVED (0x6<<17) -#define GLOBAL_OUT_NAK (0x1<<17) - -/* DWC2_UDC_OTG_DCTL device control register */ -#define NORMAL_OPERATION (0x1<<0) -#define SOFT_DISCONNECT (0x1<<1) - -/* DWC2_UDC_OTG_DAINT device all endpoint interrupt register */ -#define DAINT_OUT_BIT (16) -#define DAINT_MASK (0xFFFF) - -/* DWC2_UDC_OTG_DIEPCTL0/DOEPCTL0 device - control IN/OUT endpoint 0 control register */ -#define DEPCTL_EPENA (0x1<<31) -#define DEPCTL_EPDIS (0x1<<30) -#define DEPCTL_SETD1PID (0x1<<29) -#define DEPCTL_SETD0PID (0x1<<28) -#define DEPCTL_SNAK (0x1<<27) -#define DEPCTL_CNAK (0x1<<26) -#define DEPCTL_STALL (0x1<<21) -#define DEPCTL_TYPE_BIT (18) -#define DEPCTL_TYPE_MASK (0x3<<18) -#define DEPCTL_CTRL_TYPE (0x0<<18) -#define DEPCTL_ISO_TYPE (0x1<<18) -#define DEPCTL_BULK_TYPE (0x2<<18) -#define DEPCTL_INTR_TYPE (0x3<<18) -#define DEPCTL_USBACTEP (0x1<<15) -#define DEPCTL_NEXT_EP_BIT (11) -#define DEPCTL_MPS_BIT (0) -#define DEPCTL_MPS_MASK (0x7FF) - -#define DEPCTL0_MPS_64 (0x0<<0) -#define DEPCTL0_MPS_32 (0x1<<0) -#define DEPCTL0_MPS_16 (0x2<<0) -#define DEPCTL0_MPS_8 (0x3<<0) -#define DEPCTL_MPS_BULK_512 (512<<0) -#define DEPCTL_MPS_INT_MPS_16 (16<<0) - -#define DIEPCTL0_NEXT_EP_BIT (11) - -/* DWC2_UDC_OTG_DIEPMSK/DOEPMSK device IN/OUT endpoint - common interrupt mask register */ -/* DWC2_UDC_OTG_DIEPINTn/DOEPINTn device IN/OUT endpoint interrupt register */ -#define BACK2BACK_SETUP_RECEIVED (0x1<<6) -#define INTKNEPMIS (0x1<<5) -#define INTKN_TXFEMP (0x1<<4) -#define NON_ISO_IN_EP_TIMEOUT (0x1<<3) -#define CTRL_OUT_EP_SETUP_PHASE_DONE (0x1<<3) -#define AHB_ERROR (0x1<<2) -#define EPDISBLD (0x1<<1) -#define TRANSFER_DONE (0x1<<0) - -#define USB_PHY_CTRL_EN0 (0x1 << 0) +#define USB_PHY_CTRL_EN0 BIT(0) /* OPHYPWR */ -#define PHY_0_SLEEP (0x1 << 5) -#define OTG_DISABLE_0 (0x1 << 4) -#define ANALOG_PWRDOWN (0x1 << 3) -#define FORCE_SUSPEND_0 (0x1 << 0) +#define PHY_0_SLEEP BIT(5) +#define OTG_DISABLE_0 BIT(4) +#define ANALOG_PWRDOWN BIT(3) +#define FORCE_SUSPEND_0 BIT(0) /* URSTCON */ -#define HOST_SW_RST (0x1 << 4) -#define PHY_SW_RST1 (0x1 << 3) -#define PHYLNK_SW_RST (0x1 << 2) -#define LINK_SW_RST (0x1 << 1) -#define PHY_SW_RST0 (0x1 << 0) +#define HOST_SW_RST BIT(4) +#define PHY_SW_RST1 BIT(3) +#define PHYLNK_SW_RST BIT(2) +#define LINK_SW_RST BIT(1) +#define PHY_SW_RST0 BIT(0) /* OPHYCLK */ -#define COMMON_ON_N1 (0x1 << 7) -#define COMMON_ON_N0 (0x1 << 4) -#define ID_PULLUP0 (0x1 << 2) -#define CLK_SEL_24MHZ (0x3 << 0) -#define CLK_SEL_12MHZ (0x2 << 0) -#define CLK_SEL_48MHZ (0x0 << 0) - -#define EXYNOS4X12_ID_PULLUP0 (0x01 << 3) -#define EXYNOS4X12_COMMON_ON_N0 (0x01 << 4) +#define COMMON_ON_N1 BIT(7) +#define COMMON_ON_N0 BIT(4) +#define ID_PULLUP0 BIT(2) +#define CLK_SEL_24MHZ (0x3 << 0) +#define CLK_SEL_12MHZ (0x2 << 0) +#define CLK_SEL_48MHZ (0x0 << 0) + +#define EXYNOS4X12_ID_PULLUP0 BIT(3) +#define EXYNOS4X12_COMMON_ON_N0 BIT(4) #define EXYNOS4X12_CLK_SEL_12MHZ (0x02 << 0) #define EXYNOS4X12_CLK_SEL_24MHZ (0x05 << 0) -/* Device Configuration Register DCFG */ -#define DEV_SPEED_HIGH_SPEED_20 (0x0 << 0) -#define DEV_SPEED_FULL_SPEED_20 (0x1 << 0) -#define DEV_SPEED_LOW_SPEED_11 (0x2 << 0) -#define DEV_SPEED_FULL_SPEED_11 (0x3 << 0) -#define EP_MISS_CNT(x) (x << 18) -#define DEVICE_ADDRESS(x) (x << 4) - -/* Core Reset Register (GRSTCTL) */ -#define TX_FIFO_FLUSH (0x1 << 5) -#define RX_FIFO_FLUSH (0x1 << 4) -#define TX_FIFO_NUMBER(x) (x << 6) -#define TX_FIFO_FLUSH_ALL TX_FIFO_NUMBER(0x10) - /* Masks definitions */ -#define GINTMSK_INIT (INT_OUT_EP | INT_IN_EP | INT_RESUME | INT_ENUMDONE\ - | INT_RESET | INT_SUSPEND | INT_OTG) -#define DOEPMSK_INIT (CTRL_OUT_EP_SETUP_PHASE_DONE | AHB_ERROR|TRANSFER_DONE) -#define DIEPMSK_INIT (NON_ISO_IN_EP_TIMEOUT|AHB_ERROR|TRANSFER_DONE) -#define GAHBCFG_INIT (PTXFE_HALF | NPTXFE_HALF | MODE_DMA | BURST_INCR4\ - | GBL_INT_UNMASK) - -/* Device Endpoint X Transfer Size Register (DIEPTSIZX) */ -#define DIEPT_SIZ_PKT_CNT(x) (x << 19) -#define DIEPT_SIZ_XFER_SIZE(x) (x << 0) - -/* Device OUT Endpoint X Transfer Size Register (DOEPTSIZX) */ -#define DOEPT_SIZ_PKT_CNT(x) (x << 19) -#define DOEPT_SIZ_XFER_SIZE(x) (x << 0) -#define DOEPT_SIZ_XFER_SIZE_MAX_EP0 (0x7F << 0) -#define DOEPT_SIZ_XFER_SIZE_MAX_EP (0x7FFF << 0) - -/* Device Endpoint-N Control Register (DIEPCTLn/DOEPCTLn) */ -#define DIEPCTL_TX_FIFO_NUM(x) (x << 22) -#define DIEPCTL_TX_FIFO_NUM_MASK (~DIEPCTL_TX_FIFO_NUM(0xF)) - -/* Device ALL Endpoints Interrupt Register (DAINT) */ -#define DAINT_IN_EP_INT(x) (x << 0) -#define DAINT_OUT_EP_INT(x) (x << 16) - -/* User HW Config4 */ -#define GHWCFG4_NUM_IN_EPS_MASK (0xf << 26) -#define GHWCFG4_NUM_IN_EPS_SHIFT 26 - -/* OTG general core configuration register (OTG_GCCFG:0x38) for STM32MP1 */ -#define GGPIO_STM32_OTG_GCCFG_VBDEN BIT(21) -#define GGPIO_STM32_OTG_GCCFG_IDEN BIT(22) +#define GINTMSK_INIT (GINTSTS_WKUPINT | GINTSTS_OEPINT | GINTSTS_IEPINT | GINTSTS_ENUMDONE | \ + GINTSTS_USBRST | GINTSTS_USBSUSP | GINTSTS_OTGINT) +#define DOEPMSK_INIT (DOEPMSK_SETUPMSK | DOEPMSK_AHBERRMSK | DOEPMSK_XFERCOMPLMSK) +#define DIEPMSK_INIT (DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | DIEPMSK_XFERCOMPLMSK) +#define GAHBCFG_INIT (GAHBCFG_DMA_EN | \ + FIELD_PREP(GAHBCFG_HBSTLEN_MASK, GAHBCFG_HBSTLEN_INCR4) | \ + GAHBCFG_GLBL_INTR_EN) #endif diff --git a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c index c0408bae076..fca052b4556 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c +++ b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c @@ -19,6 +19,7 @@ #include <cpu_func.h> #include <log.h> +#include <linux/bitfield.h> #include <linux/bug.h> static u8 clear_feature_num; @@ -30,66 +31,56 @@ int clear_feature_flag; static inline void dwc2_udc_ep0_zlp(struct dwc2_udc *dev) { - u32 ep_ctrl; + writel(phys_to_bus((unsigned long)usb_ctrl_dma_addr), + ®->device_regs.in_endp[EP0_CON].diepdma); + writel(FIELD_PREP(DXEPTSIZ_PKTCNT_MASK, 1), ®->device_regs.in_endp[EP0_CON].dieptsiz); - writel(phys_to_bus((unsigned long)usb_ctrl_dma_addr), ®->in_endp[EP0_CON].diepdma); - writel(DIEPT_SIZ_PKT_CNT(1), ®->in_endp[EP0_CON].dieptsiz); - - ep_ctrl = readl(®->in_endp[EP0_CON].diepctl); - writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK, - ®->in_endp[EP0_CON].diepctl); + setbits_le32(®->device_regs.in_endp[EP0_CON].diepctl, DXEPCTL_EPENA | DXEPCTL_CNAK); debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n", - __func__, readl(®->in_endp[EP0_CON].diepctl)); + __func__, readl(®->device_regs.in_endp[EP0_CON].diepctl)); dev->ep0state = WAIT_FOR_IN_COMPLETE; } static void dwc2_udc_pre_setup(void) { - u32 ep_ctrl; - debug_cond(DEBUG_IN_EP, "%s : Prepare Setup packets.\n", __func__); - writel(DOEPT_SIZ_PKT_CNT(1) | sizeof(struct usb_ctrlrequest), - ®->out_endp[EP0_CON].doeptsiz); - writel(phys_to_bus((unsigned long)usb_ctrl_dma_addr), ®->out_endp[EP0_CON].doepdma); + writel(FIELD_PREP(DXEPTSIZ_PKTCNT_MASK, 1) | sizeof(struct usb_ctrlrequest), + ®->device_regs.out_endp[EP0_CON].doeptsiz); + writel(phys_to_bus((unsigned long)usb_ctrl_dma_addr), + ®->device_regs.out_endp[EP0_CON].doepdma); - ep_ctrl = readl(®->out_endp[EP0_CON].doepctl); - writel(ep_ctrl|DEPCTL_EPENA, ®->out_endp[EP0_CON].doepctl); + setbits_le32(®->device_regs.out_endp[EP0_CON].doepctl, DXEPCTL_EPENA); debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n", - __func__, readl(®->in_endp[EP0_CON].diepctl)); + __func__, readl(®->device_regs.in_endp[EP0_CON].diepctl)); debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DOEPCTL0 = 0x%x\n", - __func__, readl(®->out_endp[EP0_CON].doepctl)); - + __func__, readl(®->device_regs.out_endp[EP0_CON].doepctl)); } static inline void dwc2_ep0_complete_out(void) { - u32 ep_ctrl; - debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n", - __func__, readl(®->in_endp[EP0_CON].diepctl)); + __func__, readl(®->device_regs.in_endp[EP0_CON].diepctl)); debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DOEPCTL0 = 0x%x\n", - __func__, readl(®->out_endp[EP0_CON].doepctl)); + __func__, readl(®->device_regs.out_endp[EP0_CON].doepctl)); debug_cond(DEBUG_IN_EP, "%s : Prepare Complete Out packet.\n", __func__); - writel(DOEPT_SIZ_PKT_CNT(1) | sizeof(struct usb_ctrlrequest), - ®->out_endp[EP0_CON].doeptsiz); - writel(phys_to_bus((unsigned long)usb_ctrl_dma_addr), ®->out_endp[EP0_CON].doepdma); + writel(FIELD_PREP(DXEPTSIZ_PKTCNT_MASK, 1) | sizeof(struct usb_ctrlrequest), + ®->device_regs.out_endp[EP0_CON].doeptsiz); + writel(phys_to_bus((unsigned long)usb_ctrl_dma_addr), + ®->device_regs.out_endp[EP0_CON].doepdma); - ep_ctrl = readl(®->out_endp[EP0_CON].doepctl); - writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK, - ®->out_endp[EP0_CON].doepctl); + setbits_le32(®->device_regs.out_endp[EP0_CON].doepctl, DXEPCTL_EPENA | DXEPCTL_CNAK); debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n", - __func__, readl(®->in_endp[EP0_CON].diepctl)); + __func__, readl(®->device_regs.in_endp[EP0_CON].diepctl)); debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DOEPCTL0 = 0x%x\n", - __func__, readl(®->out_endp[EP0_CON].doepctl)); - + __func__, readl(®->device_regs.out_endp[EP0_CON].doepctl)); } static int setdma_rx(struct dwc2_ep *ep, struct dwc2_request *req) @@ -110,33 +101,33 @@ static int setdma_rx(struct dwc2_ep *ep, struct dwc2_request *req) else pktcnt = (length - 1)/(ep->ep.maxpacket) + 1; - ctrl = readl(®->out_endp[ep_num].doepctl); + ctrl = readl(®->device_regs.out_endp[ep_num].doepctl); invalidate_dcache_range((unsigned long) ep->dma_buf, (unsigned long) ep->dma_buf + ROUND(ep->len, CONFIG_SYS_CACHELINE_SIZE)); - writel(phys_to_bus((unsigned long)ep->dma_buf), ®->out_endp[ep_num].doepdma); - writel(DOEPT_SIZ_PKT_CNT(pktcnt) | DOEPT_SIZ_XFER_SIZE(length), - ®->out_endp[ep_num].doeptsiz); - writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, ®->out_endp[ep_num].doepctl); + writel(phys_to_bus((unsigned long)ep->dma_buf), ®->device_regs.out_endp[ep_num].doepdma); + writel(FIELD_PREP(DXEPTSIZ_PKTCNT_MASK, pktcnt) | + FIELD_PREP(DXEPTSIZ_XFERSIZE_MASK, length), + ®->device_regs.out_endp[ep_num].doeptsiz); + writel(DXEPCTL_EPENA | DXEPCTL_CNAK | ctrl, ®->device_regs.out_endp[ep_num].doepctl); debug_cond(DEBUG_OUT_EP != 0, "%s: EP%d RX DMA start : DOEPDMA = 0x%x," "DOEPTSIZ = 0x%x, DOEPCTL = 0x%x\n" "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n", __func__, ep_num, - readl(®->out_endp[ep_num].doepdma), - readl(®->out_endp[ep_num].doeptsiz), - readl(®->out_endp[ep_num].doepctl), + readl(®->device_regs.out_endp[ep_num].doepdma), + readl(®->device_regs.out_endp[ep_num].doeptsiz), + readl(®->device_regs.out_endp[ep_num].doepctl), buf, pktcnt, length); return 0; - } static int setdma_tx(struct dwc2_ep *ep, struct dwc2_request *req) { - u32 *buf, ctrl = 0; + u32 *buf; u32 length, pktcnt; u32 ep_num = ep_index(ep); @@ -159,34 +150,26 @@ static int setdma_tx(struct dwc2_ep *ep, struct dwc2_request *req) pktcnt = (length - 1)/(ep->ep.maxpacket) + 1; /* Flush the endpoint's Tx FIFO */ - writel(TX_FIFO_NUMBER(ep->fifo_num), ®->grstctl); - writel(TX_FIFO_NUMBER(ep->fifo_num) | TX_FIFO_FLUSH, ®->grstctl); - while (readl(®->grstctl) & TX_FIFO_FLUSH) - ; - - writel(phys_to_bus((unsigned long)ep->dma_buf), ®->in_endp[ep_num].diepdma); - writel(DIEPT_SIZ_PKT_CNT(pktcnt) | DIEPT_SIZ_XFER_SIZE(length), - ®->in_endp[ep_num].dieptsiz); + dwc2_flush_tx_fifo(reg, ep->fifo_num); - ctrl = readl(®->in_endp[ep_num].diepctl); + writel(phys_to_bus((unsigned long)ep->dma_buf), ®->device_regs.in_endp[ep_num].diepdma); + writel(FIELD_PREP(DXEPTSIZ_PKTCNT_MASK, pktcnt) | + FIELD_PREP(DXEPTSIZ_XFERSIZE_MASK, length), + ®->device_regs.in_endp[ep_num].dieptsiz); - /* Write the FIFO number to be used for this endpoint */ - ctrl &= DIEPCTL_TX_FIFO_NUM_MASK; - ctrl |= DIEPCTL_TX_FIFO_NUM(ep->fifo_num); - - /* Clear reserved (Next EP) bits */ - ctrl = (ctrl&~(EP_MASK<<DEPCTL_NEXT_EP_BIT)); - - writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, ®->in_endp[ep_num].diepctl); + clrsetbits_le32(®->device_regs.in_endp[ep_num].diepctl, + DXEPCTL_TXFNUM_MASK | DXEPCTL_NEXTEP_MASK, + FIELD_PREP(DXEPCTL_TXFNUM_MASK, ep->fifo_num) | + DXEPCTL_EPENA | DXEPCTL_CNAK); debug_cond(DEBUG_IN_EP, "%s:EP%d TX DMA start : DIEPDMA0 = 0x%x," "DIEPTSIZ0 = 0x%x, DIEPCTL0 = 0x%x\n" "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n", __func__, ep_num, - readl(®->in_endp[ep_num].diepdma), - readl(®->in_endp[ep_num].dieptsiz), - readl(®->in_endp[ep_num].diepctl), + readl(®->device_regs.in_endp[ep_num].diepdma), + readl(®->device_regs.in_endp[ep_num].dieptsiz), + readl(®->device_regs.in_endp[ep_num].diepctl), buf, pktcnt, length); return length; @@ -207,12 +190,12 @@ static void complete_rx(struct dwc2_udc *dev, u8 ep_num) } req = list_entry(ep->queue.next, struct dwc2_request, queue); - ep_tsr = readl(®->out_endp[ep_num].doeptsiz); + ep_tsr = readl(®->device_regs.out_endp[ep_num].doeptsiz); if (ep_num == EP0_CON) - xfer_size = (ep_tsr & DOEPT_SIZ_XFER_SIZE_MAX_EP0); + xfer_size = FIELD_PREP(DIEPTSIZ0_XFERSIZE_MASK, ep_tsr); else - xfer_size = (ep_tsr & DOEPT_SIZ_XFER_SIZE_MAX_EP); + xfer_size = FIELD_PREP(DXEPTSIZ_XFERSIZE_MASK, ep_tsr); xfer_size = ep->len - xfer_size; @@ -288,7 +271,7 @@ static void complete_tx(struct dwc2_udc *dev, u8 ep_num) req = list_entry(ep->queue.next, struct dwc2_request, queue); - ep_tsr = readl(®->in_endp[ep_num].dieptsiz); + ep_tsr = readl(®->device_regs.in_endp[ep_num].dieptsiz); xfer_size = ep->len; is_short = (xfer_size < ep->ep.maxpacket); @@ -373,23 +356,23 @@ static void process_ep_in_intr(struct dwc2_udc *dev) u32 ep_intr, ep_intr_status; u8 ep_num = 0; - ep_intr = readl(®->daint); + ep_intr = readl(®->device_regs.daint); debug_cond(DEBUG_IN_EP, "*** %s: EP In interrupt : DAINT = 0x%x\n", __func__, ep_intr); - ep_intr &= DAINT_MASK; + ep_intr = FIELD_GET(DAINT_INEP_MASK, ep_intr); while (ep_intr) { - if (ep_intr & DAINT_IN_EP_INT(1)) { - ep_intr_status = readl(®->in_endp[ep_num].diepint); + if (ep_intr & BIT(EP0_CON)) { + ep_intr_status = readl(®->device_regs.in_endp[ep_num].diepint); debug_cond(DEBUG_IN_EP, "\tEP%d-IN : DIEPINT = 0x%x\n", ep_num, ep_intr_status); /* Interrupt Clear */ - writel(ep_intr_status, ®->in_endp[ep_num].diepint); + writel(ep_intr_status, ®->device_regs.in_endp[ep_num].diepint); - if (ep_intr_status & TRANSFER_DONE) { + if (ep_intr_status & DIEPMSK_XFERCOMPLMSK) { complete_tx(dev, ep_num); if (ep_num == 0) { @@ -420,31 +403,30 @@ static void process_ep_out_intr(struct dwc2_udc *dev) u32 ep_intr, ep_intr_status; u8 ep_num = 0; u32 ep_tsr = 0, xfer_size = 0; - u32 epsiz_reg = reg->out_endp[ep_num].doeptsiz; + u32 epsiz_reg = reg->device_regs.out_endp[ep_num].doeptsiz; u32 req_size = sizeof(struct usb_ctrlrequest); - ep_intr = readl(®->daint); + ep_intr = readl(®->device_regs.daint); debug_cond(DEBUG_OUT_EP != 0, "*** %s: EP OUT interrupt : DAINT = 0x%x\n", __func__, ep_intr); - ep_intr = (ep_intr >> DAINT_OUT_BIT) & DAINT_MASK; + ep_intr = FIELD_GET(DAINT_OUTEP_MASK, ep_intr); while (ep_intr) { - if (ep_intr & 0x1) { - ep_intr_status = readl(®->out_endp[ep_num].doepint); + if (ep_intr & BIT(EP0_CON)) { + ep_intr_status = readl(®->device_regs.out_endp[ep_num].doepint); debug_cond(DEBUG_OUT_EP != 0, "\tEP%d-OUT : DOEPINT = 0x%x\n", ep_num, ep_intr_status); /* Interrupt Clear */ - writel(ep_intr_status, ®->out_endp[ep_num].doepint); + writel(ep_intr_status, ®->device_regs.out_endp[ep_num].doepint); if (ep_num == 0) { - if (ep_intr_status & TRANSFER_DONE) { + if (ep_intr_status & DOEPMSK_XFERCOMPLMSK) { ep_tsr = readl(&epsiz_reg); - xfer_size = ep_tsr & - DOEPT_SIZ_XFER_SIZE_MAX_EP0; + xfer_size = ep_tsr & DOEPTSIZ0_XFERSIZE_MASK; if (xfer_size == req_size && dev->ep0state == WAIT_FOR_SETUP) { @@ -458,14 +440,13 @@ static void process_ep_out_intr(struct dwc2_udc *dev) } } - if (ep_intr_status & - CTRL_OUT_EP_SETUP_PHASE_DONE) { + if (ep_intr_status & DOEPMSK_SETUPMSK) { debug_cond(DEBUG_OUT_EP != 0, "SETUP packet arrived\n"); dwc2_handle_ep0(dev); } } else { - if (ep_intr_status & TRANSFER_DONE) + if (ep_intr_status & DOEPMSK_XFERCOMPLMSK) complete_rx(dev, ep_num); } } @@ -486,27 +467,27 @@ static int dwc2_udc_irq(int irq, void *_dev) spin_lock_irqsave(&dev->lock, flags); - intr_status = readl(®->gintsts); - gintmsk = readl(®->gintmsk); + intr_status = readl(®->global_regs.gintsts); + gintmsk = readl(®->global_regs.gintmsk); debug_cond(DEBUG_ISR, "\n*** %s : GINTSTS=0x%x(on state %s), GINTMSK : 0x%x," "DAINT : 0x%x, DAINTMSK : 0x%x\n", __func__, intr_status, state_names[dev->ep0state], gintmsk, - readl(®->daint), readl(®->daintmsk)); + readl(®->device_regs.daint), readl(®->device_regs.daintmsk)); if (!intr_status) { spin_unlock_irqrestore(&dev->lock, flags); return IRQ_HANDLED; } - if (intr_status & INT_ENUMDONE) { + if (intr_status & GINTSTS_ENUMDONE) { debug_cond(DEBUG_ISR, "\tSpeed Detection interrupt\n"); - writel(INT_ENUMDONE, ®->gintsts); - usb_status = (readl(®->dsts) & 0x6); + writel(GINTSTS_ENUMDONE, ®->global_regs.gintsts); + usb_status = FIELD_GET(DSTS_ENUMSPD_MASK, readl(®->device_regs.dsts)); - if (usb_status & (USB_FULL_30_60MHZ | USB_FULL_48MHZ)) { + if (usb_status != DSTS_ENUMSPD_HS) { debug_cond(DEBUG_ISR, "\t\tFull Speed Detection\n"); set_max_pktsize(dev, USB_SPEED_FULL); @@ -519,16 +500,16 @@ static int dwc2_udc_irq(int irq, void *_dev) } } - if (intr_status & INT_EARLY_SUSPEND) { + if (intr_status & GINTSTS_ERLYSUSP) { debug_cond(DEBUG_ISR, "\tEarly suspend interrupt\n"); - writel(INT_EARLY_SUSPEND, ®->gintsts); + writel(GINTSTS_ERLYSUSP, ®->global_regs.gintsts); } - if (intr_status & INT_SUSPEND) { - usb_status = readl(®->dsts); + if (intr_status & GINTSTS_USBSUSP) { + usb_status = readl(®->device_regs.dsts); debug_cond(DEBUG_ISR, "\tSuspend interrupt :(DSTS):0x%x\n", usb_status); - writel(INT_SUSPEND, ®->gintsts); + writel(GINTSTS_USBSUSP, ®->global_regs.gintsts); if (dev->gadget.speed != USB_SPEED_UNKNOWN && dev->driver) { @@ -537,8 +518,8 @@ static int dwc2_udc_irq(int irq, void *_dev) } } - if (intr_status & INT_OTG) { - gotgint = readl(®->gotgint); + if (intr_status & GINTSTS_OTGINT) { + gotgint = readl(®->global_regs.gotgint); debug_cond(DEBUG_ISR, "\tOTG interrupt: (GOTGINT):0x%x\n", gotgint); @@ -551,12 +532,12 @@ static int dwc2_udc_irq(int irq, void *_dev) spin_lock_irqsave(&dev->lock, flags); } } - writel(gotgint, ®->gotgint); + writel(gotgint, ®->global_regs.gotgint); } - if (intr_status & INT_RESUME) { + if (intr_status & GINTSTS_WKUPINT) { debug_cond(DEBUG_ISR, "\tResume interrupt\n"); - writel(INT_RESUME, ®->gintsts); + writel(GINTSTS_WKUPINT, ®->global_regs.gintsts); if (dev->gadget.speed != USB_SPEED_UNKNOWN && dev->driver @@ -566,13 +547,13 @@ static int dwc2_udc_irq(int irq, void *_dev) } } - if (intr_status & INT_RESET) { - usb_status = readl(®->gotgctl); + if (intr_status & GINTSTS_USBRST) { + usb_status = readl(®->global_regs.gotgctl); debug_cond(DEBUG_ISR, "\tReset interrupt - (GOTGCTL):0x%x\n", usb_status); - writel(INT_RESET, ®->gintsts); + writel(GINTSTS_USBRST, ®->global_regs.gintsts); - if ((usb_status & 0xc0000) == (0x3 << 18)) { + if (usb_status & (GOTGCTL_ASESVLD | GOTGCTL_BSESVLD)) { if (reset_available) { debug_cond(DEBUG_ISR, "\t\tOTG core got reset (%d)!!\n", @@ -591,10 +572,10 @@ static int dwc2_udc_irq(int irq, void *_dev) } } - if (intr_status & INT_IN_EP) + if (intr_status & GINTSTS_IEPINT) process_ep_in_intr(dev); - if (intr_status & INT_OUT_EP) + if (intr_status & GINTSTS_OEPINT) process_ep_out_intr(dev); spin_unlock_irqrestore(&dev->lock, flags); @@ -676,14 +657,14 @@ static int dwc2_queue(struct usb_ep *_ep, struct usb_request *_req, req = 0; } else if (ep_is_in(ep)) { - gintsts = readl(®->gintsts); + gintsts = readl(®->global_regs.gintsts); debug_cond(DEBUG_IN_EP, "%s: ep_is_in, DWC2_UDC_OTG_GINTSTS=0x%x\n", __func__, gintsts); setdma_tx(ep, req); } else { - gintsts = readl(®->gintsts); + gintsts = readl(®->global_regs.gintsts); debug_cond(DEBUG_OUT_EP != 0, "%s:ep_is_out, DWC2_UDC_OTG_GINTSTS=0x%x\n", __func__, gintsts); @@ -765,14 +746,13 @@ static int dwc2_fifo_read(struct dwc2_ep *ep, void *cp, int max) */ static void udc_set_address(struct dwc2_udc *dev, unsigned char address) { - u32 ctrl = readl(®->dcfg); - writel(DEVICE_ADDRESS(address) | ctrl, ®->dcfg); + setbits_le32(®->device_regs.dcfg, FIELD_PREP(DCFG_DEVADDR_MASK, address)); dwc2_udc_ep0_zlp(dev); debug_cond(DEBUG_EP0 != 0, "%s: USB OTG 2.0 Device address=%d, DCFG=0x%x\n", - __func__, address, readl(®->dcfg)); + __func__, address, readl(®->device_regs.dcfg)); dev->usb_address = address; } @@ -783,19 +763,19 @@ static inline void dwc2_udc_ep0_set_stall(struct dwc2_ep *ep) u32 ep_ctrl = 0; dev = ep->dev; - ep_ctrl = readl(®->in_endp[EP0_CON].diepctl); + ep_ctrl = readl(®->device_regs.in_endp[EP0_CON].diepctl); /* set the disable and stall bits */ - if (ep_ctrl & DEPCTL_EPENA) - ep_ctrl |= DEPCTL_EPDIS; + if (ep_ctrl & DXEPCTL_EPENA) + ep_ctrl |= DXEPCTL_EPDIS; - ep_ctrl |= DEPCTL_STALL; + ep_ctrl |= DXEPCTL_STALL; - writel(ep_ctrl, ®->in_endp[EP0_CON].diepctl); + writel(ep_ctrl, ®->device_regs.in_endp[EP0_CON].diepctl); debug_cond(DEBUG_EP0 != 0, "%s: set ep%d stall, DIEPCTL0 = 0x%p\n", - __func__, ep_index(ep), ®->in_endp[EP0_CON].diepctl); + __func__, ep_index(ep), ®->device_regs.in_endp[EP0_CON].diepctl); /* * The application can only set this bit, and the core clears it, * when a SETUP token is received for this endpoint @@ -890,7 +870,6 @@ static int dwc2_udc_get_status(struct dwc2_udc *dev, { u8 ep_num = crq->wIndex & 0x3; u16 g_status = 0; - u32 ep_ctrl; debug_cond(DEBUG_SETUP != 0, "%s: *** USB_REQ_GET_STATUS\n", __func__); @@ -934,13 +913,11 @@ static int dwc2_udc_get_status(struct dwc2_udc *dev, (unsigned long) usb_ctrl + ROUND(sizeof(g_status), CONFIG_SYS_CACHELINE_SIZE)); - writel(phys_to_bus(usb_ctrl_dma_addr), ®->in_endp[EP0_CON].diepdma); - writel(DIEPT_SIZ_PKT_CNT(1) | DIEPT_SIZ_XFER_SIZE(2), - ®->in_endp[EP0_CON].dieptsiz); + writel(phys_to_bus(usb_ctrl_dma_addr), ®->device_regs.in_endp[EP0_CON].diepdma); + writel(FIELD_PREP(DXEPTSIZ_PKTCNT_MASK, 1) | FIELD_PREP(DXEPTSIZ_XFERSIZE_MASK, 2), + ®->device_regs.in_endp[EP0_CON].dieptsiz); - ep_ctrl = readl(®->in_endp[EP0_CON].diepctl); - writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK, - ®->in_endp[EP0_CON].diepctl); + setbits_le32(®->device_regs.in_endp[EP0_CON].diepctl, DXEPCTL_EPENA | DXEPCTL_CNAK); dev->ep0state = WAIT_FOR_NULL_COMPLETE; return 0; @@ -949,23 +926,18 @@ static int dwc2_udc_get_status(struct dwc2_udc *dev, static void dwc2_udc_set_nak(struct dwc2_ep *ep) { u8 ep_num; - u32 ep_ctrl = 0; ep_num = ep_index(ep); debug("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type); if (ep_is_in(ep)) { - ep_ctrl = readl(®->in_endp[ep_num].diepctl); - ep_ctrl |= DEPCTL_SNAK; - writel(ep_ctrl, ®->in_endp[ep_num].diepctl); + setbits_le32(®->device_regs.in_endp[ep_num].diepctl, DXEPCTL_SNAK); debug("%s: set NAK, DIEPCTL%d = 0x%x\n", - __func__, ep_num, readl(®->in_endp[ep_num].diepctl)); + __func__, ep_num, readl(®->device_regs.in_endp[ep_num].diepctl)); } else { - ep_ctrl = readl(®->out_endp[ep_num].doepctl); - ep_ctrl |= DEPCTL_SNAK; - writel(ep_ctrl, ®->out_endp[ep_num].doepctl); + setbits_le32(®->device_regs.out_endp[ep_num].doepctl, DXEPCTL_SNAK); debug("%s: set NAK, DOEPCTL%d = 0x%x\n", - __func__, ep_num, readl(®->out_endp[ep_num].doepctl)); + __func__, ep_num, readl(®->device_regs.out_endp[ep_num].doepctl)); } return; @@ -980,27 +952,23 @@ static void dwc2_udc_ep_set_stall(struct dwc2_ep *ep) debug("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type); if (ep_is_in(ep)) { - ep_ctrl = readl(®->in_endp[ep_num].diepctl); + ep_ctrl = readl(®->device_regs.in_endp[ep_num].diepctl); /* set the disable and stall bits */ - if (ep_ctrl & DEPCTL_EPENA) - ep_ctrl |= DEPCTL_EPDIS; + if (ep_ctrl & DXEPCTL_EPENA) + ep_ctrl |= DXEPCTL_EPDIS; - ep_ctrl |= DEPCTL_STALL; + ep_ctrl |= DXEPCTL_STALL; - writel(ep_ctrl, ®->in_endp[ep_num].diepctl); + writel(ep_ctrl, ®->device_regs.in_endp[ep_num].diepctl); debug("%s: set stall, DIEPCTL%d = 0x%x\n", - __func__, ep_num, readl(®->in_endp[ep_num].diepctl)); + __func__, ep_num, readl(®->device_regs.in_endp[ep_num].diepctl)); } else { - ep_ctrl = readl(®->out_endp[ep_num].doepctl); - /* set the stall bit */ - ep_ctrl |= DEPCTL_STALL; - - writel(ep_ctrl, ®->out_endp[ep_num].doepctl); + setbits_le32(®->device_regs.out_endp[ep_num].doepctl, DXEPCTL_STALL); debug("%s: set stall, DOEPCTL%d = 0x%x\n", - __func__, ep_num, readl(®->out_endp[ep_num].doepctl)); + __func__, ep_num, readl(®->device_regs.out_endp[ep_num].doepctl)); } return; @@ -1015,10 +983,10 @@ static void dwc2_udc_ep_clear_stall(struct dwc2_ep *ep) debug("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type); if (ep_is_in(ep)) { - ep_ctrl = readl(®->in_endp[ep_num].diepctl); + ep_ctrl = readl(®->device_regs.in_endp[ep_num].diepctl); /* clear stall bit */ - ep_ctrl &= ~DEPCTL_STALL; + ep_ctrl &= ~DXEPCTL_STALL; /* * USB Spec 9.4.5: For endpoints using data toggle, regardless @@ -1028,27 +996,27 @@ static void dwc2_udc_ep_clear_stall(struct dwc2_ep *ep) */ if (ep->bmAttributes == USB_ENDPOINT_XFER_INT || ep->bmAttributes == USB_ENDPOINT_XFER_BULK) { - ep_ctrl |= DEPCTL_SETD0PID; /* DATA0 */ + ep_ctrl |= DXEPCTL_SETD0PID; /* DATA0 */ } - writel(ep_ctrl, ®->in_endp[ep_num].diepctl); + writel(ep_ctrl, ®->device_regs.in_endp[ep_num].diepctl); debug("%s: cleared stall, DIEPCTL%d = 0x%x\n", - __func__, ep_num, readl(®->in_endp[ep_num].diepctl)); + __func__, ep_num, readl(®->device_regs.in_endp[ep_num].diepctl)); } else { - ep_ctrl = readl(®->out_endp[ep_num].doepctl); + ep_ctrl = readl(®->device_regs.out_endp[ep_num].doepctl); /* clear stall bit */ - ep_ctrl &= ~DEPCTL_STALL; + ep_ctrl &= ~DXEPCTL_STALL; if (ep->bmAttributes == USB_ENDPOINT_XFER_INT || ep->bmAttributes == USB_ENDPOINT_XFER_BULK) { - ep_ctrl |= DEPCTL_SETD0PID; /* DATA0 */ + ep_ctrl |= DXEPCTL_SETD0PID; /* DATA0 */ } - writel(ep_ctrl, ®->out_endp[ep_num].doepctl); + writel(ep_ctrl, ®->device_regs.out_endp[ep_num].doepctl); debug("%s: cleared stall, DOEPCTL%d = 0x%x\n", - __func__, ep_num, readl(®->out_endp[ep_num].doepctl)); + __func__, ep_num, readl(®->device_regs.out_endp[ep_num].doepctl)); } return; @@ -1110,11 +1078,11 @@ static void dwc2_udc_ep_activate(struct dwc2_ep *ep) /* Read DEPCTLn register */ if (ep_is_in(ep)) { - ep_ctrl = readl(®->in_endp[ep_num].diepctl); - daintmsk = 1 << ep_num; + ep_ctrl = readl(®->device_regs.in_endp[ep_num].diepctl); + daintmsk = FIELD_PREP(DAINT_INEP_MASK, BIT(ep_num)); } else { - ep_ctrl = readl(®->out_endp[ep_num].doepctl); - daintmsk = (1 << ep_num) << DAINT_OUT_BIT; + ep_ctrl = readl(®->device_regs.out_endp[ep_num].doepctl); + daintmsk = FIELD_PREP(DAINT_OUTEP_MASK, BIT(ep_num)); } debug("%s: EPCTRL%d = 0x%x, ep_is_in = %d\n", @@ -1122,30 +1090,29 @@ static void dwc2_udc_ep_activate(struct dwc2_ep *ep) /* If the EP is already active don't change the EP Control * register. */ - if (!(ep_ctrl & DEPCTL_USBACTEP)) { - ep_ctrl = (ep_ctrl & ~DEPCTL_TYPE_MASK) | - (ep->bmAttributes << DEPCTL_TYPE_BIT); - ep_ctrl = (ep_ctrl & ~DEPCTL_MPS_MASK) | - (ep->ep.maxpacket << DEPCTL_MPS_BIT); - ep_ctrl |= (DEPCTL_SETD0PID | DEPCTL_USBACTEP | DEPCTL_SNAK); + if (!(ep_ctrl & DXEPCTL_USBACTEP)) { + ep_ctrl = (ep_ctrl & ~DXEPCTL_EPTYPE_MASK) | + FIELD_PREP(DXEPCTL_EPTYPE_MASK, ep->bmAttributes); + ep_ctrl = (ep_ctrl & ~DXEPCTL_MPS_MASK) | + FIELD_PREP(DXEPCTL_MPS_MASK, ep->ep.maxpacket); + ep_ctrl |= (DXEPCTL_SETD0PID | DXEPCTL_USBACTEP | DXEPCTL_SNAK); if (ep_is_in(ep)) { - writel(ep_ctrl, ®->in_endp[ep_num].diepctl); + writel(ep_ctrl, ®->device_regs.in_endp[ep_num].diepctl); debug("%s: USB Ative EP%d, DIEPCTRL%d = 0x%x\n", __func__, ep_num, ep_num, - readl(®->in_endp[ep_num].diepctl)); + readl(®->device_regs.in_endp[ep_num].diepctl)); } else { - writel(ep_ctrl, ®->out_endp[ep_num].doepctl); + writel(ep_ctrl, ®->device_regs.out_endp[ep_num].doepctl); debug("%s: USB Ative EP%d, DOEPCTRL%d = 0x%x\n", __func__, ep_num, ep_num, - readl(®->out_endp[ep_num].doepctl)); + readl(®->device_regs.out_endp[ep_num].doepctl)); } } /* Unmask EP Interrtupt */ - writel(readl(®->daintmsk)|daintmsk, ®->daintmsk); - debug("%s: DAINTMSK = 0x%x\n", __func__, readl(®->daintmsk)); - + setbits_le32(®->device_regs.daintmsk, daintmsk); + debug("%s: DAINTMSK = 0x%x\n", __func__, readl(®->device_regs.daintmsk)); } static int dwc2_udc_clear_feature(struct usb_ep *_ep) 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/host/dwc2.c b/drivers/usb/host/dwc2.c index a9dbb85f4e6..16f21fa9083 100644 --- a/drivers/usb/host/dwc2.c +++ b/drivers/usb/host/dwc2.c @@ -19,11 +19,13 @@ #include <asm/cache.h> #include <asm/io.h> #include <dm/device_compat.h> +#include <linux/bitfield.h> #include <linux/delay.h> #include <linux/usb/otg.h> #include <power/regulator.h> #include <reset.h> +#include "../common/dwc2_core.h" #include "dwc2.h" /* Use only HC channel 0. */ @@ -37,16 +39,16 @@ struct dwc2_priv { #if CONFIG_IS_ENABLED(DM_USB) - uint8_t aligned_buffer[DWC2_DATA_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN); - uint8_t status_buffer[DWC2_STATUS_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN); + u8 aligned_buffer[DWC2_DATA_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN); + u8 status_buffer[DWC2_STATUS_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN); #ifdef CONFIG_DM_REGULATOR struct udevice *vbus_supply; #endif struct phy phy; struct clk_bulk clks; #else - uint8_t *aligned_buffer; - uint8_t *status_buffer; + u8 *aligned_buffer; + u8 *status_buffer; #endif u8 in_data_toggle[MAX_DEVICE][MAX_ENDPOINT]; u8 out_data_toggle[MAX_DEVICE][MAX_ENDPOINT]; @@ -65,10 +67,10 @@ struct dwc2_priv { #if !CONFIG_IS_ENABLED(DM_USB) /* We need cacheline-aligned buffers for DMA transfers and dcache support */ -DEFINE_ALIGN_BUFFER(uint8_t, aligned_buffer_addr, DWC2_DATA_BUF_SIZE, - ARCH_DMA_MINALIGN); -DEFINE_ALIGN_BUFFER(uint8_t, status_buffer_addr, DWC2_STATUS_BUF_SIZE, - ARCH_DMA_MINALIGN); +DEFINE_ALIGN_BUFFER(u8, aligned_buffer_addr, DWC2_DATA_BUF_SIZE, + ARCH_DMA_MINALIGN); +DEFINE_ALIGN_BUFFER(u8, status_buffer_addr, DWC2_STATUS_BUF_SIZE, + ARCH_DMA_MINALIGN); static struct dwc2_priv local; #endif @@ -83,101 +85,27 @@ static struct dwc2_priv local; */ static void init_fslspclksel(struct dwc2_core_regs *regs) { - uint32_t phyclk; + u32 phyclk; #if (DWC2_PHY_TYPE == DWC2_PHY_TYPE_FS) - phyclk = DWC2_HCFG_FSLSPCLKSEL_48_MHZ; /* Full speed PHY */ + phyclk = HCFG_FSLSPCLKSEL_48_MHZ; /* Full speed PHY */ #else /* High speed PHY running at full speed or high speed */ - phyclk = DWC2_HCFG_FSLSPCLKSEL_30_60_MHZ; + phyclk = HCFG_FSLSPCLKSEL_30_60_MHZ; #endif #ifdef DWC2_ULPI_FS_LS - uint32_t hwcfg2 = readl(®s->ghwcfg2); - uint32_t hval = (ghwcfg2 & DWC2_HWCFG2_HS_PHY_TYPE_MASK) >> - DWC2_HWCFG2_HS_PHY_TYPE_OFFSET; - uint32_t fval = (ghwcfg2 & DWC2_HWCFG2_FS_PHY_TYPE_MASK) >> - DWC2_HWCFG2_FS_PHY_TYPE_OFFSET; - - if (hval == 2 && fval == 1) - phyclk = DWC2_HCFG_FSLSPCLKSEL_48_MHZ; /* Full speed PHY */ + u32 hwcfg2 = readl(®s->global_regs.ghwcfg2); + u32 hval = FIELD_GET(GHWCFG2_HS_PHY_TYPE_MASK, ghwcfg2); + u32 fval = FIELD_GET(GHWCFG2_FS_PHY_TYPE_MASK, ghwcfg2); + + if (hval == GHWCFG2_FS_PHY_TYPE_SHARED_UTMI && fval == GHWCFG2_HS_PHY_TYPE_UTMI) + phyclk = HCFG_FSLSPCLKSEL_48_MHZ; /* Full speed PHY */ #endif clrsetbits_le32(®s->host_regs.hcfg, - DWC2_HCFG_FSLSPCLKSEL_MASK, - phyclk << DWC2_HCFG_FSLSPCLKSEL_OFFSET); -} - -/* - * Flush a Tx FIFO. - * - * @param regs Programming view of DWC_otg controller. - * @param num Tx FIFO to flush. - */ -static void dwc_otg_flush_tx_fifo(struct udevice *dev, - struct dwc2_core_regs *regs, const int num) -{ - int ret; - - writel(DWC2_GRSTCTL_TXFFLSH | (num << DWC2_GRSTCTL_TXFNUM_OFFSET), - ®s->grstctl); - ret = wait_for_bit_le32(®s->grstctl, DWC2_GRSTCTL_TXFFLSH, - false, 1000, false); - if (ret) - dev_info(dev, "%s: Timeout!\n", __func__); - - /* Wait for 3 PHY Clocks */ - udelay(1); -} - -/* - * Flush Rx FIFO. - * - * @param regs Programming view of DWC_otg controller. - */ -static void dwc_otg_flush_rx_fifo(struct udevice *dev, - struct dwc2_core_regs *regs) -{ - int ret; - - writel(DWC2_GRSTCTL_RXFFLSH, ®s->grstctl); - ret = wait_for_bit_le32(®s->grstctl, DWC2_GRSTCTL_RXFFLSH, - false, 1000, false); - if (ret) - dev_info(dev, "%s: Timeout!\n", __func__); - - /* Wait for 3 PHY Clocks */ - udelay(1); -} - -/* - * Do core a soft reset of the core. Be careful with this because it - * resets all the internal state machines of the core. - */ -static void dwc_otg_core_reset(struct udevice *dev, - struct dwc2_core_regs *regs) -{ - int ret; - - /* Wait for AHB master IDLE state. */ - ret = wait_for_bit_le32(®s->grstctl, DWC2_GRSTCTL_AHBIDLE, - true, 1000, false); - if (ret) - dev_info(dev, "%s: Timeout!\n", __func__); - - /* Core Soft Reset */ - writel(DWC2_GRSTCTL_CSFTRST, ®s->grstctl); - ret = wait_for_bit_le32(®s->grstctl, DWC2_GRSTCTL_CSFTRST, - false, 1000, false); - if (ret) - dev_info(dev, "%s: Timeout!\n", __func__); - - /* - * Wait for core to come out of reset. - * NOTE: This long sleep is _very_ important, otherwise the core will - * not stay in host mode after a connector ID change! - */ - mdelay(100); + HCFG_FSLSPCLKSEL_MASK, + FIELD_PREP(HCFG_FSLSPCLKSEL_MASK, phyclk)); } #if CONFIG_IS_ENABLED(DM_USB) && defined(CONFIG_DM_REGULATOR) @@ -244,9 +172,9 @@ static int dwc_vbus_supply_exit(struct udevice *dev) static void dwc_otg_core_host_init(struct udevice *dev, struct dwc2_core_regs *regs) { - uint32_t nptxfifosize = 0; - uint32_t ptxfifosize = 0; - uint32_t hprt0 = 0; + u32 nptxfifosize = 0; + u32 ptxfifosize = 0; + u32 hprt0 = 0; int i, ret, num_channels; /* Restart the Phy Clock */ @@ -255,67 +183,59 @@ static void dwc_otg_core_host_init(struct udevice *dev, /* Initialize Host Configuration Register */ init_fslspclksel(regs); #ifdef DWC2_DFLT_SPEED_FULL - setbits_le32(®s->host_regs.hcfg, DWC2_HCFG_FSLSSUPP); + setbits_le32(®s->host_regs.hcfg, HCFG_FSLSSUPP); #endif /* Configure data FIFO sizes */ #ifdef DWC2_ENABLE_DYNAMIC_FIFO - if (readl(®s->ghwcfg2) & DWC2_HWCFG2_DYNAMIC_FIFO) { + if (readl(®s->global_regs.ghwcfg2) & GHWCFG2_DYNAMIC_FIFO) { /* Rx FIFO */ - writel(DWC2_HOST_RX_FIFO_SIZE, ®s->grxfsiz); + writel(DWC2_HOST_RX_FIFO_SIZE, ®s->global_regs.grxfsiz); /* Non-periodic Tx FIFO */ - nptxfifosize |= DWC2_HOST_NPERIO_TX_FIFO_SIZE << - DWC2_FIFOSIZE_DEPTH_OFFSET; - nptxfifosize |= DWC2_HOST_RX_FIFO_SIZE << - DWC2_FIFOSIZE_STARTADDR_OFFSET; - writel(nptxfifosize, ®s->gnptxfsiz); + nptxfifosize |= FIELD_PREP(FIFOSIZE_DEPTH_MASK, DWC2_HOST_NPERIO_TX_FIFO_SIZE); + nptxfifosize |= FIELD_PREP(FIFOSIZE_STARTADDR_MASK, DWC2_HOST_RX_FIFO_SIZE); + writel(nptxfifosize, ®s->global_regs.gnptxfsiz); /* Periodic Tx FIFO */ - ptxfifosize |= DWC2_HOST_PERIO_TX_FIFO_SIZE << - DWC2_FIFOSIZE_DEPTH_OFFSET; - ptxfifosize |= (DWC2_HOST_RX_FIFO_SIZE + - DWC2_HOST_NPERIO_TX_FIFO_SIZE) << - DWC2_FIFOSIZE_STARTADDR_OFFSET; - writel(ptxfifosize, ®s->hptxfsiz); + ptxfifosize |= FIELD_PREP(FIFOSIZE_DEPTH_MASK, DWC2_HOST_PERIO_TX_FIFO_SIZE); + ptxfifosize |= FIELD_PREP(FIFOSIZE_STARTADDR_MASK, DWC2_HOST_RX_FIFO_SIZE + + DWC2_HOST_NPERIO_TX_FIFO_SIZE); + writel(ptxfifosize, ®s->global_regs.hptxfsiz); } #endif /* Clear Host Set HNP Enable in the OTG Control Register */ - clrbits_le32(®s->gotgctl, DWC2_GOTGCTL_HSTSETHNPEN); + clrbits_le32(®s->global_regs.gotgctl, GOTGCTL_HSTSETHNPEN); /* Make sure the FIFOs are flushed. */ - dwc_otg_flush_tx_fifo(dev, regs, 0x10); /* All Tx FIFOs */ - dwc_otg_flush_rx_fifo(dev, regs); + dwc2_flush_tx_fifo(regs, GRSTCTL_TXFNUM_ALL); /* All Tx FIFOs */ + dwc2_flush_rx_fifo(regs); /* Flush out any leftover queued requests. */ - num_channels = readl(®s->ghwcfg2); - num_channels &= DWC2_HWCFG2_NUM_HOST_CHAN_MASK; - num_channels >>= DWC2_HWCFG2_NUM_HOST_CHAN_OFFSET; - num_channels += 1; + num_channels = FIELD_GET(GHWCFG2_NUM_HOST_CHAN_MASK, readl(®s->global_regs.ghwcfg2)) + 1; for (i = 0; i < num_channels; i++) - clrsetbits_le32(®s->hc_regs[i].hcchar, - DWC2_HCCHAR_CHEN | DWC2_HCCHAR_EPDIR, - DWC2_HCCHAR_CHDIS); + clrsetbits_le32(®s->host_regs.hc[i].hcchar, HCCHAR_CHENA | HCCHAR_EPDIR, + HCCHAR_CHDIS); /* Halt all channels to put them into a known state. */ for (i = 0; i < num_channels; i++) { - clrsetbits_le32(®s->hc_regs[i].hcchar, - DWC2_HCCHAR_EPDIR, - DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS); - ret = wait_for_bit_le32(®s->hc_regs[i].hcchar, - DWC2_HCCHAR_CHEN, false, 1000, false); + clrsetbits_le32(®s->host_regs.hc[i].hcchar, + HCCHAR_EPDIR, + HCCHAR_CHENA | HCCHAR_CHDIS); + ret = wait_for_bit_le32(®s->host_regs.hc[i].hcchar, + HCCHAR_CHENA, false, 1000, false); if (ret) dev_info(dev, "%s: Timeout!\n", __func__); } /* Turn on the vbus power. */ - if (readl(®s->gintsts) & DWC2_GINTSTS_CURMODE_HOST) { - hprt0 = readl(®s->hprt0) & ~DWC2_HPRT0_W1C_MASK; - if (!(hprt0 & DWC2_HPRT0_PRTPWR)) { - hprt0 |= DWC2_HPRT0_PRTPWR; - writel(hprt0, ®s->hprt0); + if (readl(®s->global_regs.gintsts) & GINTSTS_CURMODE_HOST) { + hprt0 = readl(®s->host_regs.hprt0) & ~HPRT0_W1C_MASK; + if (!(hprt0 & HPRT0_PWR)) { + hprt0 |= HPRT0_PWR; + writel(hprt0, ®s->host_regs.hprt0); } } @@ -333,34 +253,34 @@ static void dwc_otg_core_init(struct udevice *dev) { struct dwc2_priv *priv = dev_get_priv(dev); struct dwc2_core_regs *regs = priv->regs; - uint32_t ahbcfg = 0; - uint32_t usbcfg = 0; - uint8_t brst_sz = DWC2_DMA_BURST_SIZE; + u32 ahbcfg = 0; + u32 usbcfg = 0; + u8 brst_sz = DWC2_DMA_BURST_SIZE; /* Common Initialization */ - usbcfg = readl(®s->gusbcfg); + usbcfg = readl(®s->global_regs.gusbcfg); /* Program the ULPI External VBUS bit if needed */ if (priv->ext_vbus) { - usbcfg |= DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV; + usbcfg |= GUSBCFG_ULPI_EXT_VBUS_DRV; if (!priv->oc_disable) { - usbcfg |= DWC2_GUSBCFG_ULPI_INT_VBUS_INDICATOR | - DWC2_GUSBCFG_INDICATOR_PASSTHROUGH; + usbcfg |= GUSBCFG_ULPI_INT_VBUS_IND | + GUSBCFG_INDICATORPASSTHROUGH; } } else { - usbcfg &= ~DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV; + usbcfg &= ~GUSBCFG_ULPI_EXT_VBUS_DRV; } /* Set external TS Dline pulsing */ #ifdef DWC2_TS_DLINE - usbcfg |= DWC2_GUSBCFG_TERM_SEL_DL_PULSE; + usbcfg |= GUSBCFG_TERMSELDLPULSE; #else - usbcfg &= ~DWC2_GUSBCFG_TERM_SEL_DL_PULSE; + usbcfg &= ~GUSBCFG_TERMSELDLPULSE; #endif - writel(usbcfg, ®s->gusbcfg); + writel(usbcfg, ®s->global_regs.gusbcfg); /* Reset the Controller */ - dwc_otg_core_reset(dev, regs); + dwc2_core_reset(regs); /* * This programming sequence needs to happen in FS mode before @@ -369,28 +289,28 @@ static void dwc_otg_core_init(struct udevice *dev) #if defined(DWC2_DFLT_SPEED_FULL) && \ (DWC2_PHY_TYPE == DWC2_PHY_TYPE_FS) /* If FS mode with FS PHY */ - setbits_le32(®s->gusbcfg, DWC2_GUSBCFG_PHYSEL); + setbits_le32(®s->global_regs.gusbcfg, GUSBCFG_PHYSEL); /* Reset after a PHY select */ - dwc_otg_core_reset(dev, regs); + dwc2_core_reset(regs); /* * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. * Also do this on HNP Dev/Host mode switches (done in dev_init * and host_init). */ - if (readl(®s->gintsts) & DWC2_GINTSTS_CURMODE_HOST) + if (readl(®s->global_regs.gintsts) & GINTSTS_CURMODE_HOST) init_fslspclksel(regs); #ifdef DWC2_I2C_ENABLE /* Program GUSBCFG.OtgUtmifsSel to I2C */ - setbits_le32(®s->gusbcfg, DWC2_GUSBCFG_OTGUTMIFSSEL); + setbits_le32(®s->global_regs.gusbcfg, GUSBCFG_OTG_UTMI_FS_SEL); /* Program GI2CCTL.I2CEn */ - clrsetbits_le32(®s->gi2cctl, DWC2_GI2CCTL_I2CEN | - DWC2_GI2CCTL_I2CDEVADDR_MASK, - 1 << DWC2_GI2CCTL_I2CDEVADDR_OFFSET); - setbits_le32(®s->gi2cctl, DWC2_GI2CCTL_I2CEN); + clrsetbits_le32(®s->global_regs.gi2cctl, GI2CCTL_I2CEN | + GI2CCTL_I2CDEVADDR_MASK, + FIELD_PREP(GI2CCTL_I2CDEVADDR_MASK, 1)); + setbits_le32(®s->global_regs.gi2cctl, GI2CCTL_I2CEN); #endif #else @@ -401,81 +321,76 @@ static void dwc_otg_core_init(struct udevice *dev) * soft reset so only program the first time. Do a soft reset * immediately after setting phyif. */ - usbcfg &= ~(DWC2_GUSBCFG_ULPI_UTMI_SEL | DWC2_GUSBCFG_PHYIF); - usbcfg |= DWC2_PHY_TYPE << DWC2_GUSBCFG_ULPI_UTMI_SEL_OFFSET; - - if (usbcfg & DWC2_GUSBCFG_ULPI_UTMI_SEL) { /* ULPI interface */ +#if (DWC2_PHY_TYPE == DWC2_PHY_TYPE_ULPI) + usbcfg |= GUSBCFG_ULPI_UTMI_SEL; + usbcfg &= ~GUSBCFG_PHYIF16; #ifdef DWC2_PHY_ULPI_DDR - usbcfg |= DWC2_GUSBCFG_DDRSEL; + usbcfg |= GUSBCFG_DDRSEL; #else - usbcfg &= ~DWC2_GUSBCFG_DDRSEL; -#endif - } else { /* UTMI+ interface */ + usbcfg &= ~GUSBCFG_DDRSEL; +#endif /* DWC2_PHY_ULPI_DDR */ +#elif (DWC2_PHY_TYPE == DWC2_PHY_TYPE_UTMI) + usbcfg &= ~GUSBCFG_ULPI_UTMI_SEL; #if (DWC2_UTMI_WIDTH == 16) - usbcfg |= DWC2_GUSBCFG_PHYIF; -#endif - } + usbcfg |= GUSBCFG_PHYIF16; +#else + usbcfg &= ~GUSBCFG_PHYIF16; +#endif /* DWC2_UTMI_WIDTH */ +#endif /* DWC2_PHY_TYPE */ - writel(usbcfg, ®s->gusbcfg); + writel(usbcfg, ®s->global_regs.gusbcfg); /* Reset after setting the PHY parameters */ - dwc_otg_core_reset(dev, regs); + dwc2_core_reset(regs); #endif - usbcfg = readl(®s->gusbcfg); - usbcfg &= ~(DWC2_GUSBCFG_ULPI_FSLS | DWC2_GUSBCFG_ULPI_CLK_SUS_M); + usbcfg = readl(®s->global_regs.gusbcfg); + usbcfg &= ~(GUSBCFG_ULPI_FS_LS | GUSBCFG_ULPI_CLK_SUSP_M); #ifdef DWC2_ULPI_FS_LS - uint32_t hwcfg2 = readl(®s->ghwcfg2); - uint32_t hval = (ghwcfg2 & DWC2_HWCFG2_HS_PHY_TYPE_MASK) >> - DWC2_HWCFG2_HS_PHY_TYPE_OFFSET; - uint32_t fval = (ghwcfg2 & DWC2_HWCFG2_FS_PHY_TYPE_MASK) >> - DWC2_HWCFG2_FS_PHY_TYPE_OFFSET; - if (hval == 2 && fval == 1) { - usbcfg |= DWC2_GUSBCFG_ULPI_FSLS; - usbcfg |= DWC2_GUSBCFG_ULPI_CLK_SUS_M; + u32 hwcfg2 = readl(®s->global_regs.ghwcfg2); + u32 hval = FIELD_GET(GHWCFG2_HS_PHY_TYPE_MASK, ghwcfg2); + u32 fval = FIELD_GET(GHWCFG2_FS_PHY_TYPE_MASK, ghwcfg2); + + if (hval == GHWCFG2_FS_PHY_TYPE_SHARED_UTMI && fval == GHWCFG2_HS_PHY_TYPE_UTMI) { + usbcfg |= GUSBCFG_ULPI_FS_LS; + usbcfg |= GUSBCFG_ULPI_CLK_SUSP_M; } #endif if (priv->hnp_srp_disable) - usbcfg |= DWC2_GUSBCFG_FORCEHOSTMODE; + usbcfg |= GUSBCFG_FORCEHOSTMODE; - writel(usbcfg, ®s->gusbcfg); + writel(usbcfg, ®s->global_regs.gusbcfg); /* Program the GAHBCFG Register. */ - switch (readl(®s->ghwcfg2) & DWC2_HWCFG2_ARCHITECTURE_MASK) { - case DWC2_HWCFG2_ARCHITECTURE_SLAVE_ONLY: + switch (FIELD_GET(GHWCFG2_ARCHITECTURE_MASK, readl(®s->global_regs.ghwcfg2))) { + case GHWCFG2_SLAVE_ONLY_ARCH: break; - case DWC2_HWCFG2_ARCHITECTURE_EXT_DMA: - while (brst_sz > 1) { - ahbcfg |= ahbcfg + (1 << DWC2_GAHBCFG_HBURSTLEN_OFFSET); - ahbcfg &= DWC2_GAHBCFG_HBURSTLEN_MASK; - brst_sz >>= 1; - } - + case GHWCFG2_EXT_DMA_ARCH: + ahbcfg |= FIELD_PREP(GAHBCFG_HBSTLEN_MASK, LOG2(brst_sz >> 1)); #ifdef DWC2_DMA_ENABLE - ahbcfg |= DWC2_GAHBCFG_DMAENABLE; + ahbcfg |= GAHBCFG_DMA_EN; #endif break; - - case DWC2_HWCFG2_ARCHITECTURE_INT_DMA: - ahbcfg |= DWC2_GAHBCFG_HBURSTLEN_INCR4; + case GHWCFG2_INT_DMA_ARCH: + ahbcfg |= FIELD_PREP(GAHBCFG_HBSTLEN_MASK, GAHBCFG_HBSTLEN_INCR4); #ifdef DWC2_DMA_ENABLE - ahbcfg |= DWC2_GAHBCFG_DMAENABLE; + ahbcfg |= GAHBCFG_DMA_EN; #endif break; } - writel(ahbcfg, ®s->gahbcfg); + writel(ahbcfg, ®s->global_regs.gahbcfg); /* Program the capabilities in GUSBCFG Register */ usbcfg = 0; if (!priv->hnp_srp_disable) - usbcfg |= DWC2_GUSBCFG_HNPCAP | DWC2_GUSBCFG_SRPCAP; + usbcfg |= GUSBCFG_HNPCAP | GUSBCFG_SRPCAP; #ifdef DWC2_IC_USB_CAP - usbcfg |= DWC2_GUSBCFG_IC_USB_CAP; + usbcfg |= GUSBCFG_ICUSBCAP; #endif - setbits_le32(®s->gusbcfg, usbcfg); + setbits_le32(®s->global_regs.gusbcfg, usbcfg); } /* @@ -487,19 +402,19 @@ static void dwc_otg_core_init(struct udevice *dev) * @param regs Programming view of DWC_otg controller * @param hc Information needed to initialize the host channel */ -static void dwc_otg_hc_init(struct dwc2_core_regs *regs, uint8_t hc_num, - struct usb_device *dev, uint8_t dev_addr, uint8_t ep_num, - uint8_t ep_is_in, uint8_t ep_type, uint16_t max_packet) +static void dwc_otg_hc_init(struct dwc2_core_regs *regs, u8 hc_num, + struct usb_device *dev, u8 dev_addr, u8 ep_num, + u8 ep_is_in, u8 ep_type, u16 max_packet) { - struct dwc2_hc_regs *hc_regs = ®s->hc_regs[hc_num]; - uint32_t hcchar = (dev_addr << DWC2_HCCHAR_DEVADDR_OFFSET) | - (ep_num << DWC2_HCCHAR_EPNUM_OFFSET) | - (ep_is_in << DWC2_HCCHAR_EPDIR_OFFSET) | - (ep_type << DWC2_HCCHAR_EPTYPE_OFFSET) | - (max_packet << DWC2_HCCHAR_MPS_OFFSET); + struct dwc2_hc_regs *hc_regs = ®s->host_regs.hc[hc_num]; + u32 hcchar = FIELD_PREP(HCCHAR_DEVADDR_MASK, dev_addr) | + FIELD_PREP(HCCHAR_EPNUM_MASK, ep_num) | + FIELD_PREP(HCCHAR_EPDIR, ep_is_in) | + FIELD_PREP(HCCHAR_EPTYPE_MASK, ep_type) | + FIELD_PREP(HCCHAR_MPS_MASK, max_packet); if (dev->speed == USB_SPEED_LOW) - hcchar |= DWC2_HCCHAR_LSPDDEV; + hcchar |= HCCHAR_LSPDDEV; /* * Program the HCCHARn register with the endpoint characteristics @@ -512,13 +427,13 @@ static void dwc_otg_hc_init(struct dwc2_core_regs *regs, uint8_t hc_num, } static void dwc_otg_hc_init_split(struct dwc2_hc_regs *hc_regs, - uint8_t hub_devnum, uint8_t hub_port) + u8 hub_devnum, u8 hub_port) { - uint32_t hcsplt = 0; + u32 hcsplt = 0; - hcsplt = DWC2_HCSPLT_SPLTENA; - hcsplt |= hub_devnum << DWC2_HCSPLT_HUBADDR_OFFSET; - hcsplt |= hub_port << DWC2_HCSPLT_PRTADDR_OFFSET; + hcsplt = HCSPLT_SPLTENA; + hcsplt |= FIELD_PREP(HCSPLT_HUBADDR_MASK, hub_devnum); + hcsplt |= FIELD_PREP(HCSPLT_PRTADDR_MASK, hub_port); /* Program the HCSPLIT register for SPLITs */ writel(hcsplt, &hc_regs->hcsplt); @@ -532,55 +447,58 @@ static int dwc_otg_submit_rh_msg_in_status(struct dwc2_core_regs *regs, struct usb_device *dev, void *buffer, int txlen, struct devrequest *cmd) { - uint32_t hprt0 = 0; - uint32_t port_status = 0; - uint32_t port_change = 0; + u32 hprt0 = 0; + u32 port_status = 0; + u32 port_change = 0; int len = 0; int stat = 0; switch (cmd->requesttype & ~USB_DIR_IN) { case 0: - *(uint16_t *)buffer = cpu_to_le16(1); + *(u16 *)buffer = cpu_to_le16(1); len = 2; break; case USB_RECIP_INTERFACE: case USB_RECIP_ENDPOINT: - *(uint16_t *)buffer = cpu_to_le16(0); + *(u16 *)buffer = cpu_to_le16(0); len = 2; break; case USB_TYPE_CLASS: - *(uint32_t *)buffer = cpu_to_le32(0); + *(u32 *)buffer = cpu_to_le32(0); len = 4; break; case USB_RECIP_OTHER | USB_TYPE_CLASS: - hprt0 = readl(®s->hprt0); - if (hprt0 & DWC2_HPRT0_PRTCONNSTS) + hprt0 = readl(®s->host_regs.hprt0); + if (hprt0 & HPRT0_CONNSTS) port_status |= USB_PORT_STAT_CONNECTION; - if (hprt0 & DWC2_HPRT0_PRTENA) + if (hprt0 & HPRT0_ENA) port_status |= USB_PORT_STAT_ENABLE; - if (hprt0 & DWC2_HPRT0_PRTSUSP) + if (hprt0 & HPRT0_SUSP) port_status |= USB_PORT_STAT_SUSPEND; - if (hprt0 & DWC2_HPRT0_PRTOVRCURRACT) + if (hprt0 & HPRT0_OVRCURRACT) port_status |= USB_PORT_STAT_OVERCURRENT; - if (hprt0 & DWC2_HPRT0_PRTRST) + if (hprt0 & HPRT0_RST) port_status |= USB_PORT_STAT_RESET; - if (hprt0 & DWC2_HPRT0_PRTPWR) + if (hprt0 & HPRT0_PWR) port_status |= USB_PORT_STAT_POWER; - if ((hprt0 & DWC2_HPRT0_PRTSPD_MASK) == DWC2_HPRT0_PRTSPD_LOW) + switch (FIELD_GET(HPRT0_SPD_MASK, hprt0)) { + case HPRT0_SPD_LOW_SPEED: port_status |= USB_PORT_STAT_LOW_SPEED; - else if ((hprt0 & DWC2_HPRT0_PRTSPD_MASK) == - DWC2_HPRT0_PRTSPD_HIGH) + break; + case HPRT0_SPD_HIGH_SPEED: port_status |= USB_PORT_STAT_HIGH_SPEED; + break; + } - if (hprt0 & DWC2_HPRT0_PRTENCHNG) + if (hprt0 & HPRT0_ENACHG) port_change |= USB_PORT_STAT_C_ENABLE; - if (hprt0 & DWC2_HPRT0_PRTCONNDET) + if (hprt0 & HPRT0_CONNDET) port_change |= USB_PORT_STAT_C_CONNECTION; - if (hprt0 & DWC2_HPRT0_PRTOVRCURRCHNG) + if (hprt0 & HPRT0_OVRCURRCHG) port_change |= USB_PORT_STAT_C_OVERCURRENT; - *(uint32_t *)buffer = cpu_to_le32(port_status | + *(u32 *)buffer = cpu_to_le32(port_status | (port_change << 16)); len = 4; break; @@ -601,11 +519,11 @@ static int dwc_otg_submit_rh_msg_in_descriptor(struct usb_device *dev, struct devrequest *cmd) { unsigned char data[32]; - uint32_t dsc; + u32 dsc; int len = 0; int stat = 0; - uint16_t wValue = cpu_to_le16(cmd->value); - uint16_t wLength = cpu_to_le16(cmd->length); + u16 wValue = cpu_to_le16(cmd->value); + u16 wLength = cpu_to_le16(cmd->length); switch (cmd->requesttype & ~USB_DIR_IN) { case 0: @@ -688,7 +606,7 @@ static int dwc_otg_submit_rh_msg_in_configuration(struct usb_device *dev, switch (cmd->requesttype & ~USB_DIR_IN) { case 0: - *(uint8_t *)buffer = 0x01; + *(u8 *)buffer = 0x01; len = 1; break; default: @@ -732,8 +650,8 @@ static int dwc_otg_submit_rh_msg_out(struct dwc2_priv *priv, struct dwc2_core_regs *regs = priv->regs; int len = 0; int stat = 0; - uint16_t bmrtype_breq = cmd->requesttype | (cmd->request << 8); - uint16_t wValue = cpu_to_le16(cmd->value); + u16 bmrtype_breq = cmd->requesttype | (cmd->request << 8); + u16 wValue = cpu_to_le16(cmd->value); switch (bmrtype_breq & ~USB_DIR_IN) { case (USB_REQ_CLEAR_FEATURE << 8) | USB_RECIP_ENDPOINT: @@ -743,7 +661,7 @@ static int dwc_otg_submit_rh_msg_out(struct dwc2_priv *priv, case (USB_REQ_CLEAR_FEATURE << 8) | USB_RECIP_OTHER | USB_TYPE_CLASS: switch (wValue) { case USB_PORT_FEAT_C_CONNECTION: - clrsetbits_le32(®s->hprt0, DWC2_HPRT0_W1C_MASK, DWC2_HPRT0_PRTCONNDET); + clrsetbits_le32(®s->host_regs.hprt0, HPRT0_W1C_MASK, HPRT0_CONNDET); break; } break; @@ -754,13 +672,13 @@ static int dwc_otg_submit_rh_msg_out(struct dwc2_priv *priv, break; case USB_PORT_FEAT_RESET: - clrsetbits_le32(®s->hprt0, DWC2_HPRT0_W1C_MASK, DWC2_HPRT0_PRTRST); + clrsetbits_le32(®s->host_regs.hprt0, HPRT0_W1C_MASK, HPRT0_RST); mdelay(50); - clrbits_le32(®s->hprt0, DWC2_HPRT0_W1C_MASK | DWC2_HPRT0_PRTRST); + clrbits_le32(®s->host_regs.hprt0, HPRT0_W1C_MASK | HPRT0_RST); break; case USB_PORT_FEAT_POWER: - clrsetbits_le32(®s->hprt0, DWC2_HPRT0_W1C_MASK, DWC2_HPRT0_PRTRST); + clrsetbits_le32(®s->host_regs.hprt0, HPRT0_W1C_MASK, HPRT0_RST); break; case USB_PORT_FEAT_ENABLE: @@ -806,29 +724,28 @@ static int dwc_otg_submit_rh_msg(struct dwc2_priv *priv, struct usb_device *dev, return stat; } -int wait_for_chhltd(struct dwc2_hc_regs *hc_regs, uint32_t *sub, u8 *toggle) +int wait_for_chhltd(struct dwc2_hc_regs *hc_regs, u32 *sub, u8 *toggle) { int ret; - uint32_t hcint, hctsiz; + u32 hcint, hctsiz; - ret = wait_for_bit_le32(&hc_regs->hcint, DWC2_HCINT_CHHLTD, true, + ret = wait_for_bit_le32(&hc_regs->hcint, HCINTMSK_CHHLTD, true, 2000, false); if (ret) return ret; hcint = readl(&hc_regs->hcint); hctsiz = readl(&hc_regs->hctsiz); - *sub = (hctsiz & DWC2_HCTSIZ_XFERSIZE_MASK) >> - DWC2_HCTSIZ_XFERSIZE_OFFSET; - *toggle = (hctsiz & DWC2_HCTSIZ_PID_MASK) >> DWC2_HCTSIZ_PID_OFFSET; + *sub = FIELD_GET(TSIZ_XFERSIZE_MASK, hctsiz); + *toggle = FIELD_GET(TSIZ_SC_MC_PID_MASK, hctsiz); debug("%s: HCINT=%08x sub=%u toggle=%d\n", __func__, hcint, *sub, *toggle); - if (hcint & DWC2_HCINT_XFERCOMP) + if (hcint & HCINTMSK_XFERCOMPL) return 0; - if (hcint & (DWC2_HCINT_NAK | DWC2_HCINT_FRMOVRUN)) + if (hcint & (HCINTMSK_NAK | HCINTMSK_FRMOVRUN)) return -EAGAIN; debug("%s: Error (HCINT=%08x)\n", __func__, hcint); @@ -836,10 +753,10 @@ int wait_for_chhltd(struct dwc2_hc_regs *hc_regs, uint32_t *sub, u8 *toggle) } static int dwc2_eptype[] = { - DWC2_HCCHAR_EPTYPE_ISOC, - DWC2_HCCHAR_EPTYPE_INTR, - DWC2_HCCHAR_EPTYPE_CONTROL, - DWC2_HCCHAR_EPTYPE_BULK, + HCCHAR_EPTYPE_ISOC, + HCCHAR_EPTYPE_INTR, + HCCHAR_EPTYPE_CONTROL, + HCCHAR_EPTYPE_BULK, }; static int transfer_chunk(struct dwc2_hc_regs *hc_regs, void *aligned_buffer, @@ -847,14 +764,14 @@ static int transfer_chunk(struct dwc2_hc_regs *hc_regs, void *aligned_buffer, int xfer_len, int *actual_len, int odd_frame) { int ret = 0; - uint32_t sub; + u32 sub; debug("%s: chunk: pid %d xfer_len %u pkts %u\n", __func__, *pid, xfer_len, num_packets); - writel((xfer_len << DWC2_HCTSIZ_XFERSIZE_OFFSET) | - (num_packets << DWC2_HCTSIZ_PKTCNT_OFFSET) | - (*pid << DWC2_HCTSIZ_PID_OFFSET), + writel(FIELD_PREP(TSIZ_XFERSIZE_MASK, xfer_len) | + FIELD_PREP(TSIZ_PKTCNT_MASK, num_packets) | + FIELD_PREP(TSIZ_SC_MC_PID_MASK, *pid), &hc_regs->hctsiz); if (xfer_len) { @@ -878,12 +795,12 @@ static int transfer_chunk(struct dwc2_hc_regs *hc_regs, void *aligned_buffer, writel(0x3fff, &hc_regs->hcint); /* Set host channel enable after all other setup is complete. */ - clrsetbits_le32(&hc_regs->hcchar, DWC2_HCCHAR_MULTICNT_MASK | - DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS | - DWC2_HCCHAR_ODDFRM, - (1 << DWC2_HCCHAR_MULTICNT_OFFSET) | - (odd_frame << DWC2_HCCHAR_ODDFRM_OFFSET) | - DWC2_HCCHAR_CHEN); + clrsetbits_le32(&hc_regs->hcchar, HCCHAR_MULTICNT_MASK | + HCCHAR_CHENA | HCCHAR_CHDIS | + HCCHAR_ODDFRM, + FIELD_PREP(HCCHAR_MULTICNT_MASK, 1) | + FIELD_PREP(HCCHAR_ODDFRM, odd_frame) | + HCCHAR_CHENA); ret = wait_for_chhltd(hc_regs, &sub, pid); if (ret < 0) @@ -907,7 +824,7 @@ int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev, unsigned long pipe, u8 *pid, int in, void *buffer, int len) { struct dwc2_core_regs *regs = priv->regs; - struct dwc2_hc_regs *hc_regs = ®s->hc_regs[DWC2_HC_CHANNEL]; + struct dwc2_hc_regs *hc_regs = ®s->host_regs.hc[DWC2_HC_CHANNEL]; struct dwc2_host_regs *host_regs = ®s->host_regs; int devnum = usb_pipedevice(pipe); int ep = usb_pipeendpoint(pipe); @@ -917,10 +834,10 @@ int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev, int ret = 0; int do_split = 0; int complete_split = 0; - uint32_t xfer_len; - uint32_t num_packets; + u32 xfer_len; + u32 num_packets; int stop_transfer = 0; - uint32_t max_xfer_len; + u32 max_xfer_len; int ssplit_frame_num = 0; debug("%s: msg: pipe %lx pid %d in %d len %d\n", __func__, pipe, *pid, @@ -942,11 +859,11 @@ int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev, /* Check if the target is a FS/LS device behind a HS hub */ if (dev->speed != USB_SPEED_HIGH) { - uint8_t hub_addr; - uint8_t hub_port; - uint32_t hprt0 = readl(®s->hprt0); - if ((hprt0 & DWC2_HPRT0_PRTSPD_MASK) == - DWC2_HPRT0_PRTSPD_HIGH) { + u8 hub_addr; + u8 hub_port; + u32 hprt0 = readl(®s->host_regs.hprt0); + + if (FIELD_GET(HPRT0_SPD_MASK, hprt0) == HPRT0_SPD_HIGH_SPEED) { usb_find_usb2_hub_address_port(dev, &hub_addr, &hub_port); dwc_otg_hc_init_split(hc_regs, hub_addr, hub_port); @@ -959,7 +876,7 @@ int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev, do { int actual_len = 0; - uint32_t hcint; + u32 hcint; int odd_frame = 0; xfer_len = len - done; @@ -971,11 +888,11 @@ int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev, num_packets = 1; if (complete_split) - setbits_le32(&hc_regs->hcsplt, DWC2_HCSPLT_COMPSPLT); + setbits_le32(&hc_regs->hcsplt, HCSPLT_COMPSPLT); else if (do_split) - clrbits_le32(&hc_regs->hcsplt, DWC2_HCSPLT_COMPSPLT); + clrbits_le32(&hc_regs->hcsplt, HCSPLT_COMPSPLT); - if (eptype == DWC2_HCCHAR_EPTYPE_INTR) { + if (eptype == HCCHAR_EPTYPE_INTR) { int uframe_num = readl(&host_regs->hfnum); if (!(uframe_num & 0x1)) odd_frame = 1; @@ -988,19 +905,19 @@ int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev, hcint = readl(&hc_regs->hcint); if (complete_split) { stop_transfer = 0; - if (hcint & DWC2_HCINT_NYET) { + if (hcint & HCINTMSK_NYET) { ret = 0; - int frame_num = DWC2_HFNUM_MAX_FRNUM & - readl(&host_regs->hfnum); - if (((frame_num - ssplit_frame_num) & - DWC2_HFNUM_MAX_FRNUM) > 4) + int frame_num = FIELD_GET(HFNUM_FRNUM_MASK, + readl(&host_regs->hfnum)); + + if (((frame_num - ssplit_frame_num) & HFNUM_FRNUM_MASK) > 4) ret = -EAGAIN; } else complete_split = 0; } else if (do_split) { - if (hcint & DWC2_HCINT_ACK) { - ssplit_frame_num = DWC2_HFNUM_MAX_FRNUM & - readl(&host_regs->hfnum); + if (hcint & HCINTMSK_ACK) { + ssplit_frame_num = FIELD_GET(HFNUM_FRNUM_MASK, + readl(&host_regs->hfnum)); ret = 0; complete_split = 1; } @@ -1166,7 +1083,7 @@ static int dwc2_reset(struct udevice *dev) static int dwc2_init_common(struct udevice *dev, struct dwc2_priv *priv) { struct dwc2_core_regs *regs = priv->regs; - uint32_t snpsid; + u32 snpsid; int i, j; int ret; @@ -1174,12 +1091,11 @@ static int dwc2_init_common(struct udevice *dev, struct dwc2_priv *priv) if (ret) return ret; - snpsid = readl(®s->gsnpsid); + snpsid = readl(®s->global_regs.gsnpsid); dev_info(dev, "Core Release: %x.%03x\n", snpsid >> 12 & 0xf, snpsid & 0xfff); - if ((snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_2xx && - (snpsid & DWC2_SNPSID_DEVID_MASK) != DWC2_SNPSID_DEVID_VER_3xx) { + if (FIELD_GET(GSNPSID_ID_MASK, snpsid) != GSNPSID_OTG_ID) { dev_info(dev, "SNPSID invalid (not DWC2 OTG device): %08x\n", snpsid); return -ENODEV; @@ -1200,9 +1116,9 @@ static int dwc2_init_common(struct udevice *dev, struct dwc2_priv *priv) dwc_otg_core_host_init(dev, regs); } - clrsetbits_le32(®s->hprt0, DWC2_HPRT0_W1C_MASK, DWC2_HPRT0_PRTRST); + clrsetbits_le32(®s->host_regs.hprt0, HPRT0_W1C_MASK, HPRT0_RST); mdelay(50); - clrbits_le32(®s->hprt0, DWC2_HPRT0_W1C_MASK | DWC2_HPRT0_PRTRST); + clrbits_le32(®s->host_regs.hprt0, HPRT0_W1C_MASK | HPRT0_RST); for (i = 0; i < MAX_DEVICE; i++) { for (j = 0; j < MAX_ENDPOINT; j++) { @@ -1217,7 +1133,7 @@ static int dwc2_init_common(struct udevice *dev, struct dwc2_priv *priv) * is started (the bus is scanned) and fixes the USB detection * problems with some problematic USB keys. */ - if (readl(®s->gintsts) & DWC2_GINTSTS_CURMODE_HOST) + if (readl(®s->global_regs.gintsts) & GINTSTS_CURMODE_HOST) mdelay(1000); printf("USB DWC2\n"); @@ -1228,7 +1144,7 @@ static int dwc2_init_common(struct udevice *dev, struct dwc2_priv *priv) static void dwc2_uninit_common(struct dwc2_core_regs *regs) { /* Put everything in reset. */ - clrsetbits_le32(®s->hprt0, DWC2_HPRT0_W1C_MASK, DWC2_HPRT0_PRTRST); + clrsetbits_le32(®s->host_regs.hprt0, HPRT0_W1C_MASK, HPRT0_RST); } #if !CONFIG_IS_ENABLED(DM_USB) diff --git a/drivers/usb/host/dwc2.h b/drivers/usb/host/dwc2.h index 6f022e33a19..f0bb2949649 100644 --- a/drivers/usb/host/dwc2.h +++ b/drivers/usb/host/dwc2.h @@ -6,742 +6,6 @@ #ifndef __DWC2_H__ #define __DWC2_H__ -struct dwc2_hc_regs { - u32 hcchar; /* 0x00 */ - u32 hcsplt; - u32 hcint; - u32 hcintmsk; - u32 hctsiz; /* 0x10 */ - u32 hcdma; - u32 reserved; - u32 hcdmab; -}; - -struct dwc2_host_regs { - u32 hcfg; /* 0x00 */ - u32 hfir; - u32 hfnum; - u32 _pad_0x40c; - u32 hptxsts; /* 0x10 */ - u32 haint; - u32 haintmsk; - u32 hflbaddr; -}; - -struct dwc2_core_regs { - u32 gotgctl; /* 0x000 */ - u32 gotgint; - u32 gahbcfg; - u32 gusbcfg; - u32 grstctl; /* 0x010 */ - u32 gintsts; - u32 gintmsk; - u32 grxstsr; - u32 grxstsp; /* 0x020 */ - u32 grxfsiz; - u32 gnptxfsiz; - u32 gnptxsts; - u32 gi2cctl; /* 0x030 */ - u32 gpvndctl; - u32 ggpio; - u32 guid; - u32 gsnpsid; /* 0x040 */ - u32 ghwcfg1; - u32 ghwcfg2; - u32 ghwcfg3; - u32 ghwcfg4; /* 0x050 */ - u32 glpmcfg; - u32 _pad_0x58_0x9c[42]; - u32 hptxfsiz; /* 0x100 */ - u32 dptxfsiz_dieptxf[15]; - u32 _pad_0x140_0x3fc[176]; - struct dwc2_host_regs host_regs; /* 0x400 */ - u32 _pad_0x420_0x43c[8]; - u32 hprt0; /* 0x440 */ - u32 _pad_0x444_0x4fc[47]; - struct dwc2_hc_regs hc_regs[16]; /* 0x500 */ - u32 _pad_0x700_0xe00[448]; - u32 pcgcctl; /* 0xe00 */ -}; - -#define DWC2_GOTGCTL_SESREQSCS (1 << 0) -#define DWC2_GOTGCTL_SESREQSCS_OFFSET 0 -#define DWC2_GOTGCTL_SESREQ (1 << 1) -#define DWC2_GOTGCTL_SESREQ_OFFSET 1 -#define DWC2_GOTGCTL_HSTNEGSCS (1 << 8) -#define DWC2_GOTGCTL_HSTNEGSCS_OFFSET 8 -#define DWC2_GOTGCTL_HNPREQ (1 << 9) -#define DWC2_GOTGCTL_HNPREQ_OFFSET 9 -#define DWC2_GOTGCTL_HSTSETHNPEN (1 << 10) -#define DWC2_GOTGCTL_HSTSETHNPEN_OFFSET 10 -#define DWC2_GOTGCTL_DEVHNPEN (1 << 11) -#define DWC2_GOTGCTL_DEVHNPEN_OFFSET 11 -#define DWC2_GOTGCTL_CONIDSTS (1 << 16) -#define DWC2_GOTGCTL_CONIDSTS_OFFSET 16 -#define DWC2_GOTGCTL_DBNCTIME (1 << 17) -#define DWC2_GOTGCTL_DBNCTIME_OFFSET 17 -#define DWC2_GOTGCTL_ASESVLD (1 << 18) -#define DWC2_GOTGCTL_ASESVLD_OFFSET 18 -#define DWC2_GOTGCTL_BSESVLD (1 << 19) -#define DWC2_GOTGCTL_BSESVLD_OFFSET 19 -#define DWC2_GOTGCTL_OTGVER (1 << 20) -#define DWC2_GOTGCTL_OTGVER_OFFSET 20 -#define DWC2_GOTGINT_SESENDDET (1 << 2) -#define DWC2_GOTGINT_SESENDDET_OFFSET 2 -#define DWC2_GOTGINT_SESREQSUCSTSCHNG (1 << 8) -#define DWC2_GOTGINT_SESREQSUCSTSCHNG_OFFSET 8 -#define DWC2_GOTGINT_HSTNEGSUCSTSCHNG (1 << 9) -#define DWC2_GOTGINT_HSTNEGSUCSTSCHNG_OFFSET 9 -#define DWC2_GOTGINT_RESERVER10_16_MASK (0x7F << 10) -#define DWC2_GOTGINT_RESERVER10_16_OFFSET 10 -#define DWC2_GOTGINT_HSTNEGDET (1 << 17) -#define DWC2_GOTGINT_HSTNEGDET_OFFSET 17 -#define DWC2_GOTGINT_ADEVTOUTCHNG (1 << 18) -#define DWC2_GOTGINT_ADEVTOUTCHNG_OFFSET 18 -#define DWC2_GOTGINT_DEBDONE (1 << 19) -#define DWC2_GOTGINT_DEBDONE_OFFSET 19 -#define DWC2_GAHBCFG_GLBLINTRMSK (1 << 0) -#define DWC2_GAHBCFG_GLBLINTRMSK_OFFSET 0 -#define DWC2_GAHBCFG_HBURSTLEN_SINGLE (0 << 1) -#define DWC2_GAHBCFG_HBURSTLEN_INCR (1 << 1) -#define DWC2_GAHBCFG_HBURSTLEN_INCR4 (3 << 1) -#define DWC2_GAHBCFG_HBURSTLEN_INCR8 (5 << 1) -#define DWC2_GAHBCFG_HBURSTLEN_INCR16 (7 << 1) -#define DWC2_GAHBCFG_HBURSTLEN_MASK (0xF << 1) -#define DWC2_GAHBCFG_HBURSTLEN_OFFSET 1 -#define DWC2_GAHBCFG_DMAENABLE (1 << 5) -#define DWC2_GAHBCFG_DMAENABLE_OFFSET 5 -#define DWC2_GAHBCFG_NPTXFEMPLVL_TXFEMPLVL (1 << 7) -#define DWC2_GAHBCFG_NPTXFEMPLVL_TXFEMPLVL_OFFSET 7 -#define DWC2_GAHBCFG_PTXFEMPLVL (1 << 8) -#define DWC2_GAHBCFG_PTXFEMPLVL_OFFSET 8 -#define DWC2_GUSBCFG_TOUTCAL_MASK (0x7 << 0) -#define DWC2_GUSBCFG_TOUTCAL_OFFSET 0 -#define DWC2_GUSBCFG_PHYIF (1 << 3) -#define DWC2_GUSBCFG_PHYIF_OFFSET 3 -#define DWC2_GUSBCFG_ULPI_UTMI_SEL (1 << 4) -#define DWC2_GUSBCFG_ULPI_UTMI_SEL_OFFSET 4 -#define DWC2_GUSBCFG_FSINTF (1 << 5) -#define DWC2_GUSBCFG_FSINTF_OFFSET 5 -#define DWC2_GUSBCFG_PHYSEL (1 << 6) -#define DWC2_GUSBCFG_PHYSEL_OFFSET 6 -#define DWC2_GUSBCFG_DDRSEL (1 << 7) -#define DWC2_GUSBCFG_DDRSEL_OFFSET 7 -#define DWC2_GUSBCFG_SRPCAP (1 << 8) -#define DWC2_GUSBCFG_SRPCAP_OFFSET 8 -#define DWC2_GUSBCFG_HNPCAP (1 << 9) -#define DWC2_GUSBCFG_HNPCAP_OFFSET 9 -#define DWC2_GUSBCFG_USBTRDTIM_MASK (0xF << 10) -#define DWC2_GUSBCFG_USBTRDTIM_OFFSET 10 -#define DWC2_GUSBCFG_NPTXFRWNDEN (1 << 14) -#define DWC2_GUSBCFG_NPTXFRWNDEN_OFFSET 14 -#define DWC2_GUSBCFG_PHYLPWRCLKSEL (1 << 15) -#define DWC2_GUSBCFG_PHYLPWRCLKSEL_OFFSET 15 -#define DWC2_GUSBCFG_OTGUTMIFSSEL (1 << 16) -#define DWC2_GUSBCFG_OTGUTMIFSSEL_OFFSET 16 -#define DWC2_GUSBCFG_ULPI_FSLS (1 << 17) -#define DWC2_GUSBCFG_ULPI_FSLS_OFFSET 17 -#define DWC2_GUSBCFG_ULPI_AUTO_RES (1 << 18) -#define DWC2_GUSBCFG_ULPI_AUTO_RES_OFFSET 18 -#define DWC2_GUSBCFG_ULPI_CLK_SUS_M (1 << 19) -#define DWC2_GUSBCFG_ULPI_CLK_SUS_M_OFFSET 19 -#define DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV (1 << 20) -#define DWC2_GUSBCFG_ULPI_EXT_VBUS_DRV_OFFSET 20 -#define DWC2_GUSBCFG_ULPI_INT_VBUS_INDICATOR (1 << 21) -#define DWC2_GUSBCFG_ULPI_INT_VBUS_INDICATOR_OFFSET 21 -#define DWC2_GUSBCFG_TERM_SEL_DL_PULSE (1 << 22) -#define DWC2_GUSBCFG_TERM_SEL_DL_PULSE_OFFSET 22 -#define DWC2_GUSBCFG_INDICATOR_PASSTHROUGH (1 << 24) -#define DWC2_GUSBCFG_INDICATOR_PASSTHROUGH_OFFSET 24 -#define DWC2_GUSBCFG_IC_USB_CAP (1 << 26) -#define DWC2_GUSBCFG_IC_USB_CAP_OFFSET 26 -#define DWC2_GUSBCFG_IC_TRAFFIC_PULL_REMOVE (1 << 27) -#define DWC2_GUSBCFG_IC_TRAFFIC_PULL_REMOVE_OFFSET 27 -#define DWC2_GUSBCFG_TX_END_DELAY (1 << 28) -#define DWC2_GUSBCFG_TX_END_DELAY_OFFSET 28 -#define DWC2_GUSBCFG_FORCEHOSTMODE (1 << 29) -#define DWC2_GUSBCFG_FORCEHOSTMODE_OFFSET 29 -#define DWC2_GUSBCFG_FORCEDEVMODE (1 << 30) -#define DWC2_GUSBCFG_FORCEDEVMODE_OFFSET 30 -#define DWC2_GLPMCTL_LPM_CAP_EN (1 << 0) -#define DWC2_GLPMCTL_LPM_CAP_EN_OFFSET 0 -#define DWC2_GLPMCTL_APPL_RESP (1 << 1) -#define DWC2_GLPMCTL_APPL_RESP_OFFSET 1 -#define DWC2_GLPMCTL_HIRD_MASK (0xF << 2) -#define DWC2_GLPMCTL_HIRD_OFFSET 2 -#define DWC2_GLPMCTL_REM_WKUP_EN (1 << 6) -#define DWC2_GLPMCTL_REM_WKUP_EN_OFFSET 6 -#define DWC2_GLPMCTL_EN_UTMI_SLEEP (1 << 7) -#define DWC2_GLPMCTL_EN_UTMI_SLEEP_OFFSET 7 -#define DWC2_GLPMCTL_HIRD_THRES_MASK (0x1F << 8) -#define DWC2_GLPMCTL_HIRD_THRES_OFFSET 8 -#define DWC2_GLPMCTL_LPM_RESP_MASK (0x3 << 13) -#define DWC2_GLPMCTL_LPM_RESP_OFFSET 13 -#define DWC2_GLPMCTL_PRT_SLEEP_STS (1 << 15) -#define DWC2_GLPMCTL_PRT_SLEEP_STS_OFFSET 15 -#define DWC2_GLPMCTL_SLEEP_STATE_RESUMEOK (1 << 16) -#define DWC2_GLPMCTL_SLEEP_STATE_RESUMEOK_OFFSET 16 -#define DWC2_GLPMCTL_LPM_CHAN_INDEX_MASK (0xF << 17) -#define DWC2_GLPMCTL_LPM_CHAN_INDEX_OFFSET 17 -#define DWC2_GLPMCTL_RETRY_COUNT_MASK (0x7 << 21) -#define DWC2_GLPMCTL_RETRY_COUNT_OFFSET 21 -#define DWC2_GLPMCTL_SEND_LPM (1 << 24) -#define DWC2_GLPMCTL_SEND_LPM_OFFSET 24 -#define DWC2_GLPMCTL_RETRY_COUNT_STS_MASK (0x7 << 25) -#define DWC2_GLPMCTL_RETRY_COUNT_STS_OFFSET 25 -#define DWC2_GLPMCTL_HSIC_CONNECT (1 << 30) -#define DWC2_GLPMCTL_HSIC_CONNECT_OFFSET 30 -#define DWC2_GLPMCTL_INV_SEL_HSIC (1 << 31) -#define DWC2_GLPMCTL_INV_SEL_HSIC_OFFSET 31 -#define DWC2_GRSTCTL_CSFTRST (1 << 0) -#define DWC2_GRSTCTL_CSFTRST_OFFSET 0 -#define DWC2_GRSTCTL_HSFTRST (1 << 1) -#define DWC2_GRSTCTL_HSFTRST_OFFSET 1 -#define DWC2_GRSTCTL_HSTFRM (1 << 2) -#define DWC2_GRSTCTL_HSTFRM_OFFSET 2 -#define DWC2_GRSTCTL_INTKNQFLSH (1 << 3) -#define DWC2_GRSTCTL_INTKNQFLSH_OFFSET 3 -#define DWC2_GRSTCTL_RXFFLSH (1 << 4) -#define DWC2_GRSTCTL_RXFFLSH_OFFSET 4 -#define DWC2_GRSTCTL_TXFFLSH (1 << 5) -#define DWC2_GRSTCTL_TXFFLSH_OFFSET 5 -#define DWC2_GRSTCTL_TXFNUM_MASK (0x1F << 6) -#define DWC2_GRSTCTL_TXFNUM_OFFSET 6 -#define DWC2_GRSTCTL_DMAREQ (1 << 30) -#define DWC2_GRSTCTL_DMAREQ_OFFSET 30 -#define DWC2_GRSTCTL_AHBIDLE (1 << 31) -#define DWC2_GRSTCTL_AHBIDLE_OFFSET 31 -#define DWC2_GINTMSK_MODEMISMATCH (1 << 1) -#define DWC2_GINTMSK_MODEMISMATCH_OFFSET 1 -#define DWC2_GINTMSK_OTGINTR (1 << 2) -#define DWC2_GINTMSK_OTGINTR_OFFSET 2 -#define DWC2_GINTMSK_SOFINTR (1 << 3) -#define DWC2_GINTMSK_SOFINTR_OFFSET 3 -#define DWC2_GINTMSK_RXSTSQLVL (1 << 4) -#define DWC2_GINTMSK_RXSTSQLVL_OFFSET 4 -#define DWC2_GINTMSK_NPTXFEMPTY (1 << 5) -#define DWC2_GINTMSK_NPTXFEMPTY_OFFSET 5 -#define DWC2_GINTMSK_GINNAKEFF (1 << 6) -#define DWC2_GINTMSK_GINNAKEFF_OFFSET 6 -#define DWC2_GINTMSK_GOUTNAKEFF (1 << 7) -#define DWC2_GINTMSK_GOUTNAKEFF_OFFSET 7 -#define DWC2_GINTMSK_I2CINTR (1 << 9) -#define DWC2_GINTMSK_I2CINTR_OFFSET 9 -#define DWC2_GINTMSK_ERLYSUSPEND (1 << 10) -#define DWC2_GINTMSK_ERLYSUSPEND_OFFSET 10 -#define DWC2_GINTMSK_USBSUSPEND (1 << 11) -#define DWC2_GINTMSK_USBSUSPEND_OFFSET 11 -#define DWC2_GINTMSK_USBRESET (1 << 12) -#define DWC2_GINTMSK_USBRESET_OFFSET 12 -#define DWC2_GINTMSK_ENUMDONE (1 << 13) -#define DWC2_GINTMSK_ENUMDONE_OFFSET 13 -#define DWC2_GINTMSK_ISOOUTDROP (1 << 14) -#define DWC2_GINTMSK_ISOOUTDROP_OFFSET 14 -#define DWC2_GINTMSK_EOPFRAME (1 << 15) -#define DWC2_GINTMSK_EOPFRAME_OFFSET 15 -#define DWC2_GINTMSK_EPMISMATCH (1 << 17) -#define DWC2_GINTMSK_EPMISMATCH_OFFSET 17 -#define DWC2_GINTMSK_INEPINTR (1 << 18) -#define DWC2_GINTMSK_INEPINTR_OFFSET 18 -#define DWC2_GINTMSK_OUTEPINTR (1 << 19) -#define DWC2_GINTMSK_OUTEPINTR_OFFSET 19 -#define DWC2_GINTMSK_INCOMPLISOIN (1 << 20) -#define DWC2_GINTMSK_INCOMPLISOIN_OFFSET 20 -#define DWC2_GINTMSK_INCOMPLISOOUT (1 << 21) -#define DWC2_GINTMSK_INCOMPLISOOUT_OFFSET 21 -#define DWC2_GINTMSK_PORTINTR (1 << 24) -#define DWC2_GINTMSK_PORTINTR_OFFSET 24 -#define DWC2_GINTMSK_HCINTR (1 << 25) -#define DWC2_GINTMSK_HCINTR_OFFSET 25 -#define DWC2_GINTMSK_PTXFEMPTY (1 << 26) -#define DWC2_GINTMSK_PTXFEMPTY_OFFSET 26 -#define DWC2_GINTMSK_LPMTRANRCVD (1 << 27) -#define DWC2_GINTMSK_LPMTRANRCVD_OFFSET 27 -#define DWC2_GINTMSK_CONIDSTSCHNG (1 << 28) -#define DWC2_GINTMSK_CONIDSTSCHNG_OFFSET 28 -#define DWC2_GINTMSK_DISCONNECT (1 << 29) -#define DWC2_GINTMSK_DISCONNECT_OFFSET 29 -#define DWC2_GINTMSK_SESSREQINTR (1 << 30) -#define DWC2_GINTMSK_SESSREQINTR_OFFSET 30 -#define DWC2_GINTMSK_WKUPINTR (1 << 31) -#define DWC2_GINTMSK_WKUPINTR_OFFSET 31 -#define DWC2_GINTSTS_CURMODE_DEVICE (0 << 0) -#define DWC2_GINTSTS_CURMODE_HOST (1 << 0) -#define DWC2_GINTSTS_CURMODE (1 << 0) -#define DWC2_GINTSTS_CURMODE_OFFSET 0 -#define DWC2_GINTSTS_MODEMISMATCH (1 << 1) -#define DWC2_GINTSTS_MODEMISMATCH_OFFSET 1 -#define DWC2_GINTSTS_OTGINTR (1 << 2) -#define DWC2_GINTSTS_OTGINTR_OFFSET 2 -#define DWC2_GINTSTS_SOFINTR (1 << 3) -#define DWC2_GINTSTS_SOFINTR_OFFSET 3 -#define DWC2_GINTSTS_RXSTSQLVL (1 << 4) -#define DWC2_GINTSTS_RXSTSQLVL_OFFSET 4 -#define DWC2_GINTSTS_NPTXFEMPTY (1 << 5) -#define DWC2_GINTSTS_NPTXFEMPTY_OFFSET 5 -#define DWC2_GINTSTS_GINNAKEFF (1 << 6) -#define DWC2_GINTSTS_GINNAKEFF_OFFSET 6 -#define DWC2_GINTSTS_GOUTNAKEFF (1 << 7) -#define DWC2_GINTSTS_GOUTNAKEFF_OFFSET 7 -#define DWC2_GINTSTS_I2CINTR (1 << 9) -#define DWC2_GINTSTS_I2CINTR_OFFSET 9 -#define DWC2_GINTSTS_ERLYSUSPEND (1 << 10) -#define DWC2_GINTSTS_ERLYSUSPEND_OFFSET 10 -#define DWC2_GINTSTS_USBSUSPEND (1 << 11) -#define DWC2_GINTSTS_USBSUSPEND_OFFSET 11 -#define DWC2_GINTSTS_USBRESET (1 << 12) -#define DWC2_GINTSTS_USBRESET_OFFSET 12 -#define DWC2_GINTSTS_ENUMDONE (1 << 13) -#define DWC2_GINTSTS_ENUMDONE_OFFSET 13 -#define DWC2_GINTSTS_ISOOUTDROP (1 << 14) -#define DWC2_GINTSTS_ISOOUTDROP_OFFSET 14 -#define DWC2_GINTSTS_EOPFRAME (1 << 15) -#define DWC2_GINTSTS_EOPFRAME_OFFSET 15 -#define DWC2_GINTSTS_INTOKENRX (1 << 16) -#define DWC2_GINTSTS_INTOKENRX_OFFSET 16 -#define DWC2_GINTSTS_EPMISMATCH (1 << 17) -#define DWC2_GINTSTS_EPMISMATCH_OFFSET 17 -#define DWC2_GINTSTS_INEPINT (1 << 18) -#define DWC2_GINTSTS_INEPINT_OFFSET 18 -#define DWC2_GINTSTS_OUTEPINTR (1 << 19) -#define DWC2_GINTSTS_OUTEPINTR_OFFSET 19 -#define DWC2_GINTSTS_INCOMPLISOIN (1 << 20) -#define DWC2_GINTSTS_INCOMPLISOIN_OFFSET 20 -#define DWC2_GINTSTS_INCOMPLISOOUT (1 << 21) -#define DWC2_GINTSTS_INCOMPLISOOUT_OFFSET 21 -#define DWC2_GINTSTS_PORTINTR (1 << 24) -#define DWC2_GINTSTS_PORTINTR_OFFSET 24 -#define DWC2_GINTSTS_HCINTR (1 << 25) -#define DWC2_GINTSTS_HCINTR_OFFSET 25 -#define DWC2_GINTSTS_PTXFEMPTY (1 << 26) -#define DWC2_GINTSTS_PTXFEMPTY_OFFSET 26 -#define DWC2_GINTSTS_LPMTRANRCVD (1 << 27) -#define DWC2_GINTSTS_LPMTRANRCVD_OFFSET 27 -#define DWC2_GINTSTS_CONIDSTSCHNG (1 << 28) -#define DWC2_GINTSTS_CONIDSTSCHNG_OFFSET 28 -#define DWC2_GINTSTS_DISCONNECT (1 << 29) -#define DWC2_GINTSTS_DISCONNECT_OFFSET 29 -#define DWC2_GINTSTS_SESSREQINTR (1 << 30) -#define DWC2_GINTSTS_SESSREQINTR_OFFSET 30 -#define DWC2_GINTSTS_WKUPINTR (1 << 31) -#define DWC2_GINTSTS_WKUPINTR_OFFSET 31 -#define DWC2_GRXSTS_EPNUM_MASK (0xF << 0) -#define DWC2_GRXSTS_EPNUM_OFFSET 0 -#define DWC2_GRXSTS_BCNT_MASK (0x7FF << 4) -#define DWC2_GRXSTS_BCNT_OFFSET 4 -#define DWC2_GRXSTS_DPID_MASK (0x3 << 15) -#define DWC2_GRXSTS_DPID_OFFSET 15 -#define DWC2_GRXSTS_PKTSTS_MASK (0xF << 17) -#define DWC2_GRXSTS_PKTSTS_OFFSET 17 -#define DWC2_GRXSTS_FN_MASK (0xF << 21) -#define DWC2_GRXSTS_FN_OFFSET 21 -#define DWC2_FIFOSIZE_STARTADDR_MASK (0xFFFF << 0) -#define DWC2_FIFOSIZE_STARTADDR_OFFSET 0 -#define DWC2_FIFOSIZE_DEPTH_MASK (0xFFFF << 16) -#define DWC2_FIFOSIZE_DEPTH_OFFSET 16 -#define DWC2_GNPTXSTS_NPTXFSPCAVAIL_MASK (0xFFFF << 0) -#define DWC2_GNPTXSTS_NPTXFSPCAVAIL_OFFSET 0 -#define DWC2_GNPTXSTS_NPTXQSPCAVAIL_MASK (0xFF << 16) -#define DWC2_GNPTXSTS_NPTXQSPCAVAIL_OFFSET 16 -#define DWC2_GNPTXSTS_NPTXQTOP_TERMINATE (1 << 24) -#define DWC2_GNPTXSTS_NPTXQTOP_TERMINATE_OFFSET 24 -#define DWC2_GNPTXSTS_NPTXQTOP_TOKEN_MASK (0x3 << 25) -#define DWC2_GNPTXSTS_NPTXQTOP_TOKEN_OFFSET 25 -#define DWC2_GNPTXSTS_NPTXQTOP_CHNEP_MASK (0xF << 27) -#define DWC2_GNPTXSTS_NPTXQTOP_CHNEP_OFFSET 27 -#define DWC2_DTXFSTS_TXFSPCAVAIL_MASK (0xFFFF << 0) -#define DWC2_DTXFSTS_TXFSPCAVAIL_OFFSET 0 -#define DWC2_GI2CCTL_RWDATA_MASK (0xFF << 0) -#define DWC2_GI2CCTL_RWDATA_OFFSET 0 -#define DWC2_GI2CCTL_REGADDR_MASK (0xFF << 8) -#define DWC2_GI2CCTL_REGADDR_OFFSET 8 -#define DWC2_GI2CCTL_ADDR_MASK (0x7F << 16) -#define DWC2_GI2CCTL_ADDR_OFFSET 16 -#define DWC2_GI2CCTL_I2CEN (1 << 23) -#define DWC2_GI2CCTL_I2CEN_OFFSET 23 -#define DWC2_GI2CCTL_ACK (1 << 24) -#define DWC2_GI2CCTL_ACK_OFFSET 24 -#define DWC2_GI2CCTL_I2CSUSPCTL (1 << 25) -#define DWC2_GI2CCTL_I2CSUSPCTL_OFFSET 25 -#define DWC2_GI2CCTL_I2CDEVADDR_MASK (0x3 << 26) -#define DWC2_GI2CCTL_I2CDEVADDR_OFFSET 26 -#define DWC2_GI2CCTL_RW (1 << 30) -#define DWC2_GI2CCTL_RW_OFFSET 30 -#define DWC2_GI2CCTL_BSYDNE (1 << 31) -#define DWC2_GI2CCTL_BSYDNE_OFFSET 31 -#define DWC2_HWCFG1_EP_DIR0_MASK (0x3 << 0) -#define DWC2_HWCFG1_EP_DIR0_OFFSET 0 -#define DWC2_HWCFG1_EP_DIR1_MASK (0x3 << 2) -#define DWC2_HWCFG1_EP_DIR1_OFFSET 2 -#define DWC2_HWCFG1_EP_DIR2_MASK (0x3 << 4) -#define DWC2_HWCFG1_EP_DIR2_OFFSET 4 -#define DWC2_HWCFG1_EP_DIR3_MASK (0x3 << 6) -#define DWC2_HWCFG1_EP_DIR3_OFFSET 6 -#define DWC2_HWCFG1_EP_DIR4_MASK (0x3 << 8) -#define DWC2_HWCFG1_EP_DIR4_OFFSET 8 -#define DWC2_HWCFG1_EP_DIR5_MASK (0x3 << 10) -#define DWC2_HWCFG1_EP_DIR5_OFFSET 10 -#define DWC2_HWCFG1_EP_DIR6_MASK (0x3 << 12) -#define DWC2_HWCFG1_EP_DIR6_OFFSET 12 -#define DWC2_HWCFG1_EP_DIR7_MASK (0x3 << 14) -#define DWC2_HWCFG1_EP_DIR7_OFFSET 14 -#define DWC2_HWCFG1_EP_DIR8_MASK (0x3 << 16) -#define DWC2_HWCFG1_EP_DIR8_OFFSET 16 -#define DWC2_HWCFG1_EP_DIR9_MASK (0x3 << 18) -#define DWC2_HWCFG1_EP_DIR9_OFFSET 18 -#define DWC2_HWCFG1_EP_DIR10_MASK (0x3 << 20) -#define DWC2_HWCFG1_EP_DIR10_OFFSET 20 -#define DWC2_HWCFG1_EP_DIR11_MASK (0x3 << 22) -#define DWC2_HWCFG1_EP_DIR11_OFFSET 22 -#define DWC2_HWCFG1_EP_DIR12_MASK (0x3 << 24) -#define DWC2_HWCFG1_EP_DIR12_OFFSET 24 -#define DWC2_HWCFG1_EP_DIR13_MASK (0x3 << 26) -#define DWC2_HWCFG1_EP_DIR13_OFFSET 26 -#define DWC2_HWCFG1_EP_DIR14_MASK (0x3 << 28) -#define DWC2_HWCFG1_EP_DIR14_OFFSET 28 -#define DWC2_HWCFG1_EP_DIR15_MASK (0x3 << 30) -#define DWC2_HWCFG1_EP_DIR15_OFFSET 30 -#define DWC2_HWCFG2_OP_MODE_MASK (0x7 << 0) -#define DWC2_HWCFG2_OP_MODE_OFFSET 0 -#define DWC2_HWCFG2_ARCHITECTURE_SLAVE_ONLY (0x0 << 3) -#define DWC2_HWCFG2_ARCHITECTURE_EXT_DMA (0x1 << 3) -#define DWC2_HWCFG2_ARCHITECTURE_INT_DMA (0x2 << 3) -#define DWC2_HWCFG2_ARCHITECTURE_MASK (0x3 << 3) -#define DWC2_HWCFG2_ARCHITECTURE_OFFSET 3 -#define DWC2_HWCFG2_POINT2POINT (1 << 5) -#define DWC2_HWCFG2_POINT2POINT_OFFSET 5 -#define DWC2_HWCFG2_HS_PHY_TYPE_MASK (0x3 << 6) -#define DWC2_HWCFG2_HS_PHY_TYPE_OFFSET 6 -#define DWC2_HWCFG2_FS_PHY_TYPE_MASK (0x3 << 8) -#define DWC2_HWCFG2_FS_PHY_TYPE_OFFSET 8 -#define DWC2_HWCFG2_NUM_DEV_EP_MASK (0xF << 10) -#define DWC2_HWCFG2_NUM_DEV_EP_OFFSET 10 -#define DWC2_HWCFG2_NUM_HOST_CHAN_MASK (0xF << 14) -#define DWC2_HWCFG2_NUM_HOST_CHAN_OFFSET 14 -#define DWC2_HWCFG2_PERIO_EP_SUPPORTED (1 << 18) -#define DWC2_HWCFG2_PERIO_EP_SUPPORTED_OFFSET 18 -#define DWC2_HWCFG2_DYNAMIC_FIFO (1 << 19) -#define DWC2_HWCFG2_DYNAMIC_FIFO_OFFSET 19 -#define DWC2_HWCFG2_MULTI_PROC_INT (1 << 20) -#define DWC2_HWCFG2_MULTI_PROC_INT_OFFSET 20 -#define DWC2_HWCFG2_NONPERIO_TX_Q_DEPTH_MASK (0x3 << 22) -#define DWC2_HWCFG2_NONPERIO_TX_Q_DEPTH_OFFSET 22 -#define DWC2_HWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK (0x3 << 24) -#define DWC2_HWCFG2_HOST_PERIO_TX_Q_DEPTH_OFFSET 24 -#define DWC2_HWCFG2_DEV_TOKEN_Q_DEPTH_MASK (0x1F << 26) -#define DWC2_HWCFG2_DEV_TOKEN_Q_DEPTH_OFFSET 26 -#define DWC2_HWCFG3_XFER_SIZE_CNTR_WIDTH_MASK (0xF << 0) -#define DWC2_HWCFG3_XFER_SIZE_CNTR_WIDTH_OFFSET 0 -#define DWC2_HWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK (0x7 << 4) -#define DWC2_HWCFG3_PACKET_SIZE_CNTR_WIDTH_OFFSET 4 -#define DWC2_HWCFG3_OTG_FUNC (1 << 7) -#define DWC2_HWCFG3_OTG_FUNC_OFFSET 7 -#define DWC2_HWCFG3_I2C (1 << 8) -#define DWC2_HWCFG3_I2C_OFFSET 8 -#define DWC2_HWCFG3_VENDOR_CTRL_IF (1 << 9) -#define DWC2_HWCFG3_VENDOR_CTRL_IF_OFFSET 9 -#define DWC2_HWCFG3_OPTIONAL_FEATURES (1 << 10) -#define DWC2_HWCFG3_OPTIONAL_FEATURES_OFFSET 10 -#define DWC2_HWCFG3_SYNCH_RESET_TYPE (1 << 11) -#define DWC2_HWCFG3_SYNCH_RESET_TYPE_OFFSET 11 -#define DWC2_HWCFG3_OTG_ENABLE_IC_USB (1 << 12) -#define DWC2_HWCFG3_OTG_ENABLE_IC_USB_OFFSET 12 -#define DWC2_HWCFG3_OTG_ENABLE_HSIC (1 << 13) -#define DWC2_HWCFG3_OTG_ENABLE_HSIC_OFFSET 13 -#define DWC2_HWCFG3_OTG_LPM_EN (1 << 15) -#define DWC2_HWCFG3_OTG_LPM_EN_OFFSET 15 -#define DWC2_HWCFG3_DFIFO_DEPTH_MASK (0xFFFF << 16) -#define DWC2_HWCFG3_DFIFO_DEPTH_OFFSET 16 -#define DWC2_HWCFG4_NUM_DEV_PERIO_IN_EP_MASK (0xF << 0) -#define DWC2_HWCFG4_NUM_DEV_PERIO_IN_EP_OFFSET 0 -#define DWC2_HWCFG4_POWER_OPTIMIZ (1 << 4) -#define DWC2_HWCFG4_POWER_OPTIMIZ_OFFSET 4 -#define DWC2_HWCFG4_MIN_AHB_FREQ_MASK (0x1FF << 5) -#define DWC2_HWCFG4_MIN_AHB_FREQ_OFFSET 5 -#define DWC2_HWCFG4_UTMI_PHY_DATA_WIDTH_MASK (0x3 << 14) -#define DWC2_HWCFG4_UTMI_PHY_DATA_WIDTH_OFFSET 14 -#define DWC2_HWCFG4_NUM_DEV_MODE_CTRL_EP_MASK (0xF << 16) -#define DWC2_HWCFG4_NUM_DEV_MODE_CTRL_EP_OFFSET 16 -#define DWC2_HWCFG4_IDDIG_FILT_EN (1 << 20) -#define DWC2_HWCFG4_IDDIG_FILT_EN_OFFSET 20 -#define DWC2_HWCFG4_VBUS_VALID_FILT_EN (1 << 21) -#define DWC2_HWCFG4_VBUS_VALID_FILT_EN_OFFSET 21 -#define DWC2_HWCFG4_A_VALID_FILT_EN (1 << 22) -#define DWC2_HWCFG4_A_VALID_FILT_EN_OFFSET 22 -#define DWC2_HWCFG4_B_VALID_FILT_EN (1 << 23) -#define DWC2_HWCFG4_B_VALID_FILT_EN_OFFSET 23 -#define DWC2_HWCFG4_SESSION_END_FILT_EN (1 << 24) -#define DWC2_HWCFG4_SESSION_END_FILT_EN_OFFSET 24 -#define DWC2_HWCFG4_DED_FIFO_EN (1 << 25) -#define DWC2_HWCFG4_DED_FIFO_EN_OFFSET 25 -#define DWC2_HWCFG4_NUM_IN_EPS_MASK (0xF << 26) -#define DWC2_HWCFG4_NUM_IN_EPS_OFFSET 26 -#define DWC2_HWCFG4_DESC_DMA (1 << 30) -#define DWC2_HWCFG4_DESC_DMA_OFFSET 30 -#define DWC2_HWCFG4_DESC_DMA_DYN (1 << 31) -#define DWC2_HWCFG4_DESC_DMA_DYN_OFFSET 31 -#define DWC2_HCFG_FSLSPCLKSEL_30_60_MHZ 0 -#define DWC2_HCFG_FSLSPCLKSEL_48_MHZ 1 -#define DWC2_HCFG_FSLSPCLKSEL_6_MHZ 2 -#define DWC2_HCFG_FSLSPCLKSEL_MASK (0x3 << 0) -#define DWC2_HCFG_FSLSPCLKSEL_OFFSET 0 -#define DWC2_HCFG_FSLSSUPP (1 << 2) -#define DWC2_HCFG_FSLSSUPP_OFFSET 2 -#define DWC2_HCFG_DESCDMA (1 << 23) -#define DWC2_HCFG_DESCDMA_OFFSET 23 -#define DWC2_HCFG_FRLISTEN_MASK (0x3 << 24) -#define DWC2_HCFG_FRLISTEN_OFFSET 24 -#define DWC2_HCFG_PERSCHEDENA (1 << 26) -#define DWC2_HCFG_PERSCHEDENA_OFFSET 26 -#define DWC2_HCFG_PERSCHEDSTAT (1 << 27) -#define DWC2_HCFG_PERSCHEDSTAT_OFFSET 27 -#define DWC2_HFIR_FRINT_MASK (0xFFFF << 0) -#define DWC2_HFIR_FRINT_OFFSET 0 -#define DWC2_HFNUM_FRNUM_MASK (0xFFFF << 0) -#define DWC2_HFNUM_FRNUM_OFFSET 0 -#define DWC2_HFNUM_FRREM_MASK (0xFFFF << 16) -#define DWC2_HFNUM_FRREM_OFFSET 16 -#define DWC2_HFNUM_MAX_FRNUM 0x3FFF -#define DWC2_HPTXSTS_PTXFSPCAVAIL_MASK (0xFFFF << 0) -#define DWC2_HPTXSTS_PTXFSPCAVAIL_OFFSET 0 -#define DWC2_HPTXSTS_PTXQSPCAVAIL_MASK (0xFF << 16) -#define DWC2_HPTXSTS_PTXQSPCAVAIL_OFFSET 16 -#define DWC2_HPTXSTS_PTXQTOP_TERMINATE (1 << 24) -#define DWC2_HPTXSTS_PTXQTOP_TERMINATE_OFFSET 24 -#define DWC2_HPTXSTS_PTXQTOP_TOKEN_MASK (0x3 << 25) -#define DWC2_HPTXSTS_PTXQTOP_TOKEN_OFFSET 25 -#define DWC2_HPTXSTS_PTXQTOP_CHNUM_MASK (0xF << 27) -#define DWC2_HPTXSTS_PTXQTOP_CHNUM_OFFSET 27 -#define DWC2_HPTXSTS_PTXQTOP_ODD (1 << 31) -#define DWC2_HPTXSTS_PTXQTOP_ODD_OFFSET 31 -#define DWC2_HPRT0_PRTCONNSTS (1 << 0) -#define DWC2_HPRT0_PRTCONNSTS_OFFSET 0 -#define DWC2_HPRT0_PRTCONNDET (1 << 1) -#define DWC2_HPRT0_PRTCONNDET_OFFSET 1 -#define DWC2_HPRT0_PRTENA (1 << 2) -#define DWC2_HPRT0_PRTENA_OFFSET 2 -#define DWC2_HPRT0_PRTENCHNG (1 << 3) -#define DWC2_HPRT0_PRTENCHNG_OFFSET 3 -#define DWC2_HPRT0_PRTOVRCURRACT (1 << 4) -#define DWC2_HPRT0_PRTOVRCURRACT_OFFSET 4 -#define DWC2_HPRT0_PRTOVRCURRCHNG (1 << 5) -#define DWC2_HPRT0_PRTOVRCURRCHNG_OFFSET 5 -#define DWC2_HPRT0_PRTRES (1 << 6) -#define DWC2_HPRT0_PRTRES_OFFSET 6 -#define DWC2_HPRT0_PRTSUSP (1 << 7) -#define DWC2_HPRT0_PRTSUSP_OFFSET 7 -#define DWC2_HPRT0_PRTRST (1 << 8) -#define DWC2_HPRT0_PRTRST_OFFSET 8 -#define DWC2_HPRT0_PRTLNSTS_MASK (0x3 << 10) -#define DWC2_HPRT0_PRTLNSTS_OFFSET 10 -#define DWC2_HPRT0_PRTPWR (1 << 12) -#define DWC2_HPRT0_PRTPWR_OFFSET 12 -#define DWC2_HPRT0_PRTTSTCTL_MASK (0xF << 13) -#define DWC2_HPRT0_PRTTSTCTL_OFFSET 13 -#define DWC2_HPRT0_PRTSPD_HIGH (0 << 17) -#define DWC2_HPRT0_PRTSPD_FULL (1 << 17) -#define DWC2_HPRT0_PRTSPD_LOW (2 << 17) -#define DWC2_HPRT0_PRTSPD_MASK (0x3 << 17) -#define DWC2_HPRT0_PRTSPD_OFFSET 17 -#define DWC2_HPRT0_W1C_MASK (DWC2_HPRT0_PRTCONNDET | \ - DWC2_HPRT0_PRTENA | \ - DWC2_HPRT0_PRTENCHNG | \ - DWC2_HPRT0_PRTOVRCURRCHNG) -#define DWC2_HAINT_CH0 (1 << 0) -#define DWC2_HAINT_CH0_OFFSET 0 -#define DWC2_HAINT_CH1 (1 << 1) -#define DWC2_HAINT_CH1_OFFSET 1 -#define DWC2_HAINT_CH2 (1 << 2) -#define DWC2_HAINT_CH2_OFFSET 2 -#define DWC2_HAINT_CH3 (1 << 3) -#define DWC2_HAINT_CH3_OFFSET 3 -#define DWC2_HAINT_CH4 (1 << 4) -#define DWC2_HAINT_CH4_OFFSET 4 -#define DWC2_HAINT_CH5 (1 << 5) -#define DWC2_HAINT_CH5_OFFSET 5 -#define DWC2_HAINT_CH6 (1 << 6) -#define DWC2_HAINT_CH6_OFFSET 6 -#define DWC2_HAINT_CH7 (1 << 7) -#define DWC2_HAINT_CH7_OFFSET 7 -#define DWC2_HAINT_CH8 (1 << 8) -#define DWC2_HAINT_CH8_OFFSET 8 -#define DWC2_HAINT_CH9 (1 << 9) -#define DWC2_HAINT_CH9_OFFSET 9 -#define DWC2_HAINT_CH10 (1 << 10) -#define DWC2_HAINT_CH10_OFFSET 10 -#define DWC2_HAINT_CH11 (1 << 11) -#define DWC2_HAINT_CH11_OFFSET 11 -#define DWC2_HAINT_CH12 (1 << 12) -#define DWC2_HAINT_CH12_OFFSET 12 -#define DWC2_HAINT_CH13 (1 << 13) -#define DWC2_HAINT_CH13_OFFSET 13 -#define DWC2_HAINT_CH14 (1 << 14) -#define DWC2_HAINT_CH14_OFFSET 14 -#define DWC2_HAINT_CH15 (1 << 15) -#define DWC2_HAINT_CH15_OFFSET 15 -#define DWC2_HAINT_CHINT_MASK 0xffff -#define DWC2_HAINT_CHINT_OFFSET 0 -#define DWC2_HAINTMSK_CH0 (1 << 0) -#define DWC2_HAINTMSK_CH0_OFFSET 0 -#define DWC2_HAINTMSK_CH1 (1 << 1) -#define DWC2_HAINTMSK_CH1_OFFSET 1 -#define DWC2_HAINTMSK_CH2 (1 << 2) -#define DWC2_HAINTMSK_CH2_OFFSET 2 -#define DWC2_HAINTMSK_CH3 (1 << 3) -#define DWC2_HAINTMSK_CH3_OFFSET 3 -#define DWC2_HAINTMSK_CH4 (1 << 4) -#define DWC2_HAINTMSK_CH4_OFFSET 4 -#define DWC2_HAINTMSK_CH5 (1 << 5) -#define DWC2_HAINTMSK_CH5_OFFSET 5 -#define DWC2_HAINTMSK_CH6 (1 << 6) -#define DWC2_HAINTMSK_CH6_OFFSET 6 -#define DWC2_HAINTMSK_CH7 (1 << 7) -#define DWC2_HAINTMSK_CH7_OFFSET 7 -#define DWC2_HAINTMSK_CH8 (1 << 8) -#define DWC2_HAINTMSK_CH8_OFFSET 8 -#define DWC2_HAINTMSK_CH9 (1 << 9) -#define DWC2_HAINTMSK_CH9_OFFSET 9 -#define DWC2_HAINTMSK_CH10 (1 << 10) -#define DWC2_HAINTMSK_CH10_OFFSET 10 -#define DWC2_HAINTMSK_CH11 (1 << 11) -#define DWC2_HAINTMSK_CH11_OFFSET 11 -#define DWC2_HAINTMSK_CH12 (1 << 12) -#define DWC2_HAINTMSK_CH12_OFFSET 12 -#define DWC2_HAINTMSK_CH13 (1 << 13) -#define DWC2_HAINTMSK_CH13_OFFSET 13 -#define DWC2_HAINTMSK_CH14 (1 << 14) -#define DWC2_HAINTMSK_CH14_OFFSET 14 -#define DWC2_HAINTMSK_CH15 (1 << 15) -#define DWC2_HAINTMSK_CH15_OFFSET 15 -#define DWC2_HAINTMSK_CHINT_MASK 0xffff -#define DWC2_HAINTMSK_CHINT_OFFSET 0 -#define DWC2_HCCHAR_MPS_MASK (0x7FF << 0) -#define DWC2_HCCHAR_MPS_OFFSET 0 -#define DWC2_HCCHAR_EPNUM_MASK (0xF << 11) -#define DWC2_HCCHAR_EPNUM_OFFSET 11 -#define DWC2_HCCHAR_EPDIR (1 << 15) -#define DWC2_HCCHAR_EPDIR_OFFSET 15 -#define DWC2_HCCHAR_LSPDDEV (1 << 17) -#define DWC2_HCCHAR_LSPDDEV_OFFSET 17 -#define DWC2_HCCHAR_EPTYPE_CONTROL 0 -#define DWC2_HCCHAR_EPTYPE_ISOC 1 -#define DWC2_HCCHAR_EPTYPE_BULK 2 -#define DWC2_HCCHAR_EPTYPE_INTR 3 -#define DWC2_HCCHAR_EPTYPE_MASK (0x3 << 18) -#define DWC2_HCCHAR_EPTYPE_OFFSET 18 -#define DWC2_HCCHAR_MULTICNT_MASK (0x3 << 20) -#define DWC2_HCCHAR_MULTICNT_OFFSET 20 -#define DWC2_HCCHAR_DEVADDR_MASK (0x7F << 22) -#define DWC2_HCCHAR_DEVADDR_OFFSET 22 -#define DWC2_HCCHAR_ODDFRM (1 << 29) -#define DWC2_HCCHAR_ODDFRM_OFFSET 29 -#define DWC2_HCCHAR_CHDIS (1 << 30) -#define DWC2_HCCHAR_CHDIS_OFFSET 30 -#define DWC2_HCCHAR_CHEN (1 << 31) -#define DWC2_HCCHAR_CHEN_OFFSET 31 -#define DWC2_HCSPLT_PRTADDR_MASK (0x7F << 0) -#define DWC2_HCSPLT_PRTADDR_OFFSET 0 -#define DWC2_HCSPLT_HUBADDR_MASK (0x7F << 7) -#define DWC2_HCSPLT_HUBADDR_OFFSET 7 -#define DWC2_HCSPLT_XACTPOS_MASK (0x3 << 14) -#define DWC2_HCSPLT_XACTPOS_OFFSET 14 -#define DWC2_HCSPLT_COMPSPLT (1 << 16) -#define DWC2_HCSPLT_COMPSPLT_OFFSET 16 -#define DWC2_HCSPLT_SPLTENA (1 << 31) -#define DWC2_HCSPLT_SPLTENA_OFFSET 31 -#define DWC2_HCINT_XFERCOMP (1 << 0) -#define DWC2_HCINT_XFERCOMP_OFFSET 0 -#define DWC2_HCINT_CHHLTD (1 << 1) -#define DWC2_HCINT_CHHLTD_OFFSET 1 -#define DWC2_HCINT_AHBERR (1 << 2) -#define DWC2_HCINT_AHBERR_OFFSET 2 -#define DWC2_HCINT_STALL (1 << 3) -#define DWC2_HCINT_STALL_OFFSET 3 -#define DWC2_HCINT_NAK (1 << 4) -#define DWC2_HCINT_NAK_OFFSET 4 -#define DWC2_HCINT_ACK (1 << 5) -#define DWC2_HCINT_ACK_OFFSET 5 -#define DWC2_HCINT_NYET (1 << 6) -#define DWC2_HCINT_NYET_OFFSET 6 -#define DWC2_HCINT_XACTERR (1 << 7) -#define DWC2_HCINT_XACTERR_OFFSET 7 -#define DWC2_HCINT_BBLERR (1 << 8) -#define DWC2_HCINT_BBLERR_OFFSET 8 -#define DWC2_HCINT_FRMOVRUN (1 << 9) -#define DWC2_HCINT_FRMOVRUN_OFFSET 9 -#define DWC2_HCINT_DATATGLERR (1 << 10) -#define DWC2_HCINT_DATATGLERR_OFFSET 10 -#define DWC2_HCINT_BNA (1 << 11) -#define DWC2_HCINT_BNA_OFFSET 11 -#define DWC2_HCINT_XCS_XACT (1 << 12) -#define DWC2_HCINT_XCS_XACT_OFFSET 12 -#define DWC2_HCINT_FRM_LIST_ROLL (1 << 13) -#define DWC2_HCINT_FRM_LIST_ROLL_OFFSET 13 -#define DWC2_HCINTMSK_XFERCOMPL (1 << 0) -#define DWC2_HCINTMSK_XFERCOMPL_OFFSET 0 -#define DWC2_HCINTMSK_CHHLTD (1 << 1) -#define DWC2_HCINTMSK_CHHLTD_OFFSET 1 -#define DWC2_HCINTMSK_AHBERR (1 << 2) -#define DWC2_HCINTMSK_AHBERR_OFFSET 2 -#define DWC2_HCINTMSK_STALL (1 << 3) -#define DWC2_HCINTMSK_STALL_OFFSET 3 -#define DWC2_HCINTMSK_NAK (1 << 4) -#define DWC2_HCINTMSK_NAK_OFFSET 4 -#define DWC2_HCINTMSK_ACK (1 << 5) -#define DWC2_HCINTMSK_ACK_OFFSET 5 -#define DWC2_HCINTMSK_NYET (1 << 6) -#define DWC2_HCINTMSK_NYET_OFFSET 6 -#define DWC2_HCINTMSK_XACTERR (1 << 7) -#define DWC2_HCINTMSK_XACTERR_OFFSET 7 -#define DWC2_HCINTMSK_BBLERR (1 << 8) -#define DWC2_HCINTMSK_BBLERR_OFFSET 8 -#define DWC2_HCINTMSK_FRMOVRUN (1 << 9) -#define DWC2_HCINTMSK_FRMOVRUN_OFFSET 9 -#define DWC2_HCINTMSK_DATATGLERR (1 << 10) -#define DWC2_HCINTMSK_DATATGLERR_OFFSET 10 -#define DWC2_HCINTMSK_BNA (1 << 11) -#define DWC2_HCINTMSK_BNA_OFFSET 11 -#define DWC2_HCINTMSK_XCS_XACT (1 << 12) -#define DWC2_HCINTMSK_XCS_XACT_OFFSET 12 -#define DWC2_HCINTMSK_FRM_LIST_ROLL (1 << 13) -#define DWC2_HCINTMSK_FRM_LIST_ROLL_OFFSET 13 -#define DWC2_HCTSIZ_XFERSIZE_MASK 0x7ffff -#define DWC2_HCTSIZ_XFERSIZE_OFFSET 0 -#define DWC2_HCTSIZ_SCHINFO_MASK 0xff -#define DWC2_HCTSIZ_SCHINFO_OFFSET 0 -#define DWC2_HCTSIZ_NTD_MASK (0xff << 8) -#define DWC2_HCTSIZ_NTD_OFFSET 8 -#define DWC2_HCTSIZ_PKTCNT_MASK (0x3ff << 19) -#define DWC2_HCTSIZ_PKTCNT_OFFSET 19 -#define DWC2_HCTSIZ_PID_MASK (0x3 << 29) -#define DWC2_HCTSIZ_PID_OFFSET 29 -#define DWC2_HCTSIZ_DOPNG (1 << 31) -#define DWC2_HCTSIZ_DOPNG_OFFSET 31 -#define DWC2_HCDMA_CTD_MASK (0xFF << 3) -#define DWC2_HCDMA_CTD_OFFSET 3 -#define DWC2_HCDMA_DMA_ADDR_MASK (0x1FFFFF << 11) -#define DWC2_HCDMA_DMA_ADDR_OFFSET 11 -#define DWC2_PCGCCTL_STOPPCLK (1 << 0) -#define DWC2_PCGCCTL_STOPPCLK_OFFSET 0 -#define DWC2_PCGCCTL_GATEHCLK (1 << 1) -#define DWC2_PCGCCTL_GATEHCLK_OFFSET 1 -#define DWC2_PCGCCTL_PWRCLMP (1 << 2) -#define DWC2_PCGCCTL_PWRCLMP_OFFSET 2 -#define DWC2_PCGCCTL_RSTPDWNMODULE (1 << 3) -#define DWC2_PCGCCTL_RSTPDWNMODULE_OFFSET 3 -#define DWC2_PCGCCTL_PHYSUSPENDED (1 << 4) -#define DWC2_PCGCCTL_PHYSUSPENDED_OFFSET 4 -#define DWC2_PCGCCTL_ENBL_SLEEP_GATING (1 << 5) -#define DWC2_PCGCCTL_ENBL_SLEEP_GATING_OFFSET 5 -#define DWC2_PCGCCTL_PHY_IN_SLEEP (1 << 6) -#define DWC2_PCGCCTL_PHY_IN_SLEEP_OFFSET 6 -#define DWC2_PCGCCTL_DEEP_SLEEP (1 << 7) -#define DWC2_PCGCCTL_DEEP_SLEEP_OFFSET 7 -#define DWC2_SNPSID_DEVID_VER_2xx (0x4f542 << 12) -#define DWC2_SNPSID_DEVID_VER_3xx (0x4f543 << 12) -#define DWC2_SNPSID_DEVID_MASK (0xfffff << 12) -#define DWC2_SNPSID_DEVID_OFFSET 12 - /* Host controller specific */ #define DWC2_HC_PID_DATA0 0 #define DWC2_HC_PID_DATA2 1 @@ -750,13 +14,13 @@ struct dwc2_core_regs { #define DWC2_HC_PID_SETUP 3 /* roothub.a masks */ -#define RH_A_NDP (0xff << 0) /* number of downstream ports */ -#define RH_A_PSM (1 << 8) /* power switching mode */ -#define RH_A_NPS (1 << 9) /* no power switching */ -#define RH_A_DT (1 << 10) /* device type (mbz) */ -#define RH_A_OCPM (1 << 11) /* over current protection mode */ -#define RH_A_NOCP (1 << 12) /* no over current protection */ -#define RH_A_POTPGT (0xff << 24) /* power on to power good time */ +#define RH_A_NDP GENMASK(7, 0) /* number of downstream ports */ +#define RH_A_PSM BIT(8) /* power switching mode */ +#define RH_A_NPS BIT(9) /* no power switching */ +#define RH_A_DT BIT(10) /* device type (mbz) */ +#define RH_A_OCPM BIT(11) /* over current protection mode */ +#define RH_A_NOCP BIT(12) /* no over current protection */ +#define RH_A_POTPGT GENMASK(31, 24) /* power on to power good time */ /* roothub.b masks */ #define RH_B_DR 0x0000ffff /* device removable flags */ 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/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/nexell_display.c b/drivers/video/nexell_display.c index 7bda33fb16e..ea3776258a0 100644 --- a/drivers/video/nexell_display.c +++ b/drivers/video/nexell_display.c @@ -10,6 +10,7 @@ #include <config.h> #include <command.h> #include <dm.h> +#include <env.h> #include <mapmem.h> #include <malloc.h> #include <linux/compat.h> 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/virtio/virtio_net.h b/drivers/virtio/virtio_net.h index c92bae52690..3adcb19aead 100644 --- a/drivers/virtio/virtio_net.h +++ b/drivers/virtio/virtio_net.h @@ -9,8 +9,7 @@ #ifndef _LINUX_VIRTIO_NET_H #define _LINUX_VIRTIO_NET_H -/* TODO: needs to be removed! */ -#define ETH_ALEN 6 +#include <linux/if_ether.h> /* The feature bitmap for virtio net */ 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), +}; |