diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/reset/Kconfig | 8 | ||||
-rw-r--r-- | drivers/reset/Makefile | 1 | ||||
-rw-r--r-- | drivers/reset/reset-at91.c | 141 | ||||
-rw-r--r-- | drivers/sysreset/sysreset_at91.c | 10 |
4 files changed, 151 insertions, 9 deletions
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 4cb0ba0850..e4039d7474 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -211,4 +211,12 @@ config RESET_DRA7 help Support for TI DRA7-RESET subsystem. Basic Assert/Deassert is supported. + +config RESET_AT91 + bool "Enable support for Microchip/Atmel Reset Controller driver" + depends on DM_RESET && ARCH_AT91 + help + This enables the Reset Controller driver support for Microchip/Atmel + SoCs. Mainly used to expose assert/deassert methods to other drivers + that require it. endmenu diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 0620b62809..6c8b45ecba 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o obj-$(CONFIG_RESET_SCMI) += reset-scmi.o obj-$(CONFIG_RESET_ZYNQMP) += reset-zynqmp.o obj-$(CONFIG_RESET_DRA7) += reset-dra7.o +obj-$(CONFIG_RESET_AT91) += reset-at91.o diff --git a/drivers/reset/reset-at91.c b/drivers/reset/reset-at91.c new file mode 100644 index 0000000000..165c87acdc --- /dev/null +++ b/drivers/reset/reset-at91.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Support for Atmel/Microchip Reset Controller. + * + * Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries + * + * Author: Sergiu Moga <sergiu.moga@microchip.com> + */ + +#include <clk.h> +#include <asm/io.h> +#include <dm.h> +#include <dm/lists.h> +#include <reset-uclass.h> +#include <asm/arch/at91_rstc.h> +#include <dt-bindings/reset/sama7g5-reset.h> + +struct at91_reset { + void __iomem *dev_base; + struct at91_reset_data *data; +}; + +struct at91_reset_data { + u32 n_device_reset; + u8 device_reset_min_id; + u8 device_reset_max_id; +}; + +static const struct at91_reset_data sama7g5_data = { + .n_device_reset = 3, + .device_reset_min_id = SAMA7G5_RESET_USB_PHY1, + .device_reset_max_id = SAMA7G5_RESET_USB_PHY3, +}; + +static int at91_rst_update(struct at91_reset *reset, unsigned long id, + bool assert) +{ + u32 val; + + if (!reset->dev_base) + return 0; + + val = readl(reset->dev_base); + if (assert) + val |= BIT(id); + else + val &= ~BIT(id); + writel(val, reset->dev_base); + + return 0; +} + +static int at91_reset_of_xlate(struct reset_ctl *reset_ctl, + struct ofnode_phandle_args *args) +{ + struct at91_reset *reset = dev_get_priv(reset_ctl->dev); + + if (!reset->data->n_device_reset || + args->args[0] < reset->data->device_reset_min_id || + args->args[0] > reset->data->device_reset_max_id) + return -EINVAL; + + reset_ctl->id = args->args[0]; + + return 0; +} + +static int at91_rst_assert(struct reset_ctl *reset_ctl) +{ + struct at91_reset *reset = dev_get_priv(reset_ctl->dev); + + return at91_rst_update(reset, reset_ctl->id, true); +} + +static int at91_rst_deassert(struct reset_ctl *reset_ctl) +{ + struct at91_reset *reset = dev_get_priv(reset_ctl->dev); + + return at91_rst_update(reset, reset_ctl->id, false); +} + +struct reset_ops at91_reset_ops = { + .of_xlate = at91_reset_of_xlate, + .rst_assert = at91_rst_assert, + .rst_deassert = at91_rst_deassert, +}; + +static int at91_reset_probe(struct udevice *dev) +{ + struct at91_reset *reset = dev_get_priv(dev); + struct clk sclk; + int ret; + + reset->data = (struct at91_reset_data *)dev_get_driver_data(dev); + reset->dev_base = dev_remap_addr_index(dev, 1); + if (reset->data && reset->data->n_device_reset && !reset->dev_base) + return -EINVAL; + + ret = clk_get_by_index(dev, 0, &sclk); + if (ret) + return ret; + + return clk_prepare_enable(&sclk); +} + +static int at91_reset_bind(struct udevice *dev) +{ + struct udevice *at91_sysreset; + + if (CONFIG_IS_ENABLED(SYSRESET_AT91)) + return device_bind_driver_to_node(dev, "at91_sysreset", + "at91_sysreset", + dev_ofnode(dev), + &at91_sysreset); + + return 0; +} + +static const struct udevice_id at91_reset_ids[] = { + { + .compatible = "microchip,sama7g5-rstc", + .data = (ulong)&sama7g5_data, + }, + { + .compatible = "atmel,sama5d3-rstc", + }, + { + .compatible = "microchip,sam9x60-rstc", + }, + { } +}; + +U_BOOT_DRIVER(at91_reset) = { + .name = "at91_reset", + .id = UCLASS_RESET, + .of_match = at91_reset_ids, + .bind = at91_reset_bind, + .probe = at91_reset_probe, + .priv_auto = sizeof(struct at91_reset), + .ops = &at91_reset_ops, +}; diff --git a/drivers/sysreset/sysreset_at91.c b/drivers/sysreset/sysreset_at91.c index 6119a29927..fc85f31ebf 100644 --- a/drivers/sysreset/sysreset_at91.c +++ b/drivers/sysreset/sysreset_at91.c @@ -56,17 +56,9 @@ static struct sysreset_ops at91_sysreset = { .request = at91_sysreset_request, }; -static const struct udevice_id a91_sysreset_ids[] = { - { .compatible = "atmel,sama5d3-rstc" }, - { .compatible = "microchip,sam9x60-rstc" }, - { .compatible = "microchip,sama7g5-rstc" }, - { } -}; - U_BOOT_DRIVER(sysreset_at91) = { .id = UCLASS_SYSRESET, - .name = "at91_reset", + .name = "at91_sysreset", .ops = &at91_sysreset, .probe = at91_sysreset_probe, - .of_match = a91_sysreset_ids, }; |