diff options
Diffstat (limited to 'drivers/reset/stm32')
-rw-r--r-- | drivers/reset/stm32/Kconfig | 23 | ||||
-rw-r--r-- | drivers/reset/stm32/Makefile | 9 | ||||
-rw-r--r-- | drivers/reset/stm32/stm32-reset-core.c | 92 | ||||
-rw-r--r-- | drivers/reset/stm32/stm32-reset-core.h | 31 | ||||
-rw-r--r-- | drivers/reset/stm32/stm32-reset-mp1.c | 55 | ||||
-rw-r--r-- | drivers/reset/stm32/stm32-reset-mp25.c | 159 | ||||
-rw-r--r-- | drivers/reset/stm32/stm32-reset.c | 43 |
7 files changed, 412 insertions, 0 deletions
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, +}; |