[PATCH v3 1/5] reset: Add reset_reset() and reset_reset_bulk() API
Maarten Brock
Maarten.Brock at sttls.nl
Mon May 18 12:21:05 CEST 2026
Hello Michal,
Although properly commented, I find the reset_reset_bulk() implementation
counterintuitive. Are we so certain that the Linux implementation is the right
and obvious one? I personally would prefer to have it assert all resets at the
same time. It is faster and prevents races if the resets are interdependent.
Kind regards,
Maarten Brock
> -----Original Message-----
> From: U-Boot <u-boot-bounces at lists.denx.de> On Behalf Of Michal Simek
> Sent: Wednesday 13 May 2026 11:42
> To: u-boot at lists.denx.de; git at amd.com; Simon Glass <sjg at chromium.org>
> Cc: Tom Rini <trini at konsulko.com>
> Subject: [PATCH v3 1/5] reset: Add reset_reset() and reset_reset_bulk() API
>
> Add reset_reset() and reset_reset_bulk() functions to the reset
> controller API. These functions assert and then deassert reset signals
> in a single call, providing a convenient way to pulse/toggle a reset
> line.
>
> This mimics the Linux kernel's reset_control_reset() and
> reset_control_bulk_reset() APIs. The new functions are useful for
> drivers that need to cycle a reset line during initialization or
> error recovery but with also passing delay parameter.
>
> If a driver implements the rst_reset op, it will be called directly
> with the delay parameter. Otherwise, the reset core performs
> reset_assert(), optional udelay(), and reset_deassert() as fallback.
>
> Signed-off-by: Michal Simek <michal.simek at amd.com>
> Reviewed-by: Simon Glass <sjg at chromium.org>
> ---
>
> Changes in v3:
> - extend function documentation
>
> Changes in v2:
> - Add delay_us parameter to specify delay between assert and deassert
> - Pass delay_us to rst_reset op so drivers can use it if needed
> - Return -ENOSYS in stubs when !CONFIG_DM_RESET (like clk.h)
> - Fix line length to stay within 80 characters
>
> drivers/reset/reset-uclass.c | 34 +++++++++++++++++++++++++
> include/reset-uclass.h | 19 ++++++++++++++
> include/reset.h | 49 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 102 insertions(+)
>
> diff --git a/drivers/reset/reset-uclass.c b/drivers/reset/reset-uclass.c
> index fe4cebf54f15..c199e3e5da71 100644
> --- a/drivers/reset/reset-uclass.c
> +++ b/drivers/reset/reset-uclass.c
> @@ -13,6 +13,7 @@
> #include <reset-uclass.h>
> #include <dm/devres.h>
> #include <dm/lists.h>
> +#include <linux/delay.h>
>
> static inline struct reset_ops *reset_dev_ops(struct udevice *dev)
> {
> @@ -225,6 +226,39 @@ int reset_deassert_bulk(struct reset_ctl_bulk *bulk)
> return 0;
> }
>
> +int reset_reset(struct reset_ctl *reset_ctl, ulong delay_us)
> +{
> + struct reset_ops *ops = reset_dev_ops(reset_ctl->dev);
> + int ret;
> +
> + debug("%s(reset_ctl=%p, delay_us=%lu)\n", __func__, reset_ctl,
> + delay_us);
> +
> + if (ops->rst_reset)
> + return ops->rst_reset(reset_ctl, delay_us);
> +
> + ret = reset_assert(reset_ctl);
> + if (ret < 0)
> + return ret;
> +
> + udelay(delay_us);
> +
> + return reset_deassert(reset_ctl);
> +}
> +
> +int reset_reset_bulk(struct reset_ctl_bulk *bulk, ulong delay_us)
> +{
> + int i, ret;
> +
> + for (i = 0; i < bulk->count; i++) {
> + ret = reset_reset(&bulk->resets[i], delay_us);
> + if (ret < 0)
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> int reset_status(struct reset_ctl *reset_ctl)
> {
> struct reset_ops *ops = reset_dev_ops(reset_ctl->dev);
> diff --git a/include/reset-uclass.h b/include/reset-uclass.h
> index 9a0696dd1e3b..7af090b60b57 100644
> --- a/include/reset-uclass.h
> +++ b/include/reset-uclass.h
> @@ -76,6 +76,25 @@ struct reset_ops {
> * @return 0 if OK, or a negative error code.
> */
> int (*rst_deassert)(struct reset_ctl *reset_ctl);
> + /**
> + * rst_reset - Reset a HW module.
> + *
> + * This optional function triggers a reset pulse on the reset line.
> + * If not implemented, reset_reset() falls back to rst_assert(),
> + * udelay(@delay_us), then rst_deassert(); that delay is therefore
> + * observed only on the fallback path.
> + *
> + * When rst_reset is provided, @delay_us is controller-specific: the
> + * implementation should honour it if the hardware needs a minimum
> + * assertion time before release. It may ignore @delay_us when the
> + * pulse shape is fixed elsewhere (for example a firmware pulse).
> + *
> + * @reset_ctl: The reset signal to pulse.
> + * @delay_us: Minimum delay in microseconds between assert and
> + * deassert where applicable; see above.
> + * @return 0 if OK, or a negative error code.
> + */
> + int (*rst_reset)(struct reset_ctl *reset_ctl, ulong delay_us);
> /**
> * rst_status - Check reset signal status.
> *
> diff --git a/include/reset.h b/include/reset.h
> index 036a786d2ace..58574b983f66 100644
> --- a/include/reset.h
> +++ b/include/reset.h
> @@ -320,6 +320,45 @@ int reset_deassert(struct reset_ctl *reset_ctl);
> */
> int reset_deassert_bulk(struct reset_ctl_bulk *bulk);
>
> +/**
> + * reset_reset - Reset a HW module by asserting and deasserting a reset signal.
> + *
> + * This function will assert and then deassert the specified reset signal,
> + * thus resetting the affected HW module. This is a convenience function
> + * that combines reset_assert() and reset_deassert().
> + *
> + * If the controller implements struct reset_ops.rst_reset, that callback
> + * is used and @delay_us is interpreted as documented there. Otherwise the
> + * core performs reset_assert(), udelay(@delay_us), then reset_deassert().
> + *
> + * @reset_ctl: A reset control struct that was previously successfully
> + * requested by reset_get_by_*().
> + * @delay_us: Delay in microseconds between assert and deassert on the
> + * fallback path; meaning is driver-specific when rst_reset is used.
> + * Use 0 for no delay on the fallback path.
> + * Return: 0 if OK, or a negative error code.
> + */
> +int reset_reset(struct reset_ctl *reset_ctl, ulong delay_us);
> +
> +/**
> + * reset_reset_bulk - Reset all HW modules in a reset control bulk struct.
> + *
> + * This calls reset_reset() on each entry in order. Each line therefore
> + * completes its own assert/delay/deassert (or controller rst_reset) before
> + * the next entry starts. That matches Linux reset_control_bulk_reset().
> + *
> + * When several lines must stay asserted together for @delay_us (typical
> + * multi-reset controllers), use reset_assert_bulk(), udelay(@delay_us),
> + * and reset_deassert_bulk() instead.
> + *
> + * @bulk: A reset control bulk struct that was previously successfully
> + * requested by reset_get_bulk().
> + * @delay_us: Delay in microseconds passed to each reset_reset(); see
> + * reset_reset() and struct reset_ops.rst_reset.
> + * Return: 0 if OK, or a negative error code.
> + */
> +int reset_reset_bulk(struct reset_ctl_bulk *bulk, ulong delay_us);
> +
> /**
> * rst_status - Check reset signal status.
> *
> @@ -443,6 +482,16 @@ static inline int reset_deassert_bulk(struct reset_ctl_bulk *bulk)
> return 0;
> }
>
> +static inline int reset_reset(struct reset_ctl *reset_ctl, ulong delay_us)
> +{
> + return -ENOSYS;
> +}
> +
> +static inline int reset_reset_bulk(struct reset_ctl_bulk *bulk, ulong delay_us)
> +{
> + return -ENOSYS;
> +}
> +
> static inline int reset_status(struct reset_ctl *reset_ctl)
> {
> return -ENOTSUPP;
> --
> 2.43.0
More information about the U-Boot
mailing list