
In order to have the device model describe the module reset bits on sunxi (well, at least for anything newer than sun6i), we need a (rather simple) driver for 'allwinner,sun6i-a31-clock-reset' nodes.
Signed-off-by: Philipp Tomsich philipp.tomsich@theobroma-systems.com --- drivers/reset/Kconfig | 9 ++++ drivers/reset/Makefile | 1 + drivers/reset/reset-sunxi.c | 107 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 drivers/reset/reset-sunxi.c
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index c42b0bc..8db25fc 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -43,4 +43,13 @@ config RESET_UNIPHIER Say Y if you want to control reset signals provided by System Control block, Media I/O block, Peripheral Block.
+config RESET_SUNXI + bool "Reset controller driver for Allwiner SoCs" + depends on DM_RESET && ARCH_SUNXI + default y + help + Support for reset controllers on Allwinner SoCs. + Say Y if you want to control reset signals provided by CCU (e.g. sun50i) + or PRCM (e.g. sun6i, sun9i) blocks. + endmenu diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 5c4305c..0086da9 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -1,10 +1,11 @@ # Copyright (c) 2016, NVIDIA CORPORATION. # # SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_DM_RESET) += reset-uclass.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-reset.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-reset-test.o obj-$(CONFIG_TEGRA_CAR_RESET) += tegra-car-reset.o obj-$(CONFIG_TEGRA186_RESET) += tegra186-reset.o obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o +obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o diff --git a/drivers/reset/reset-sunxi.c b/drivers/reset/reset-sunxi.c new file mode 100644 index 0000000..b667ca1 --- /dev/null +++ b/drivers/reset/reset-sunxi.c @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2017 Theobroma Systems Design und Consulting GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <reset-uclass.h> +#include <dm/device.h> +#include <linux/bitops.h> +#include <linux/io.h> +#include <linux/sizes.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct sunxi_reset_priv { + void __iomem *base; + size_t size; +}; + +static int sunxi_reset_request(struct reset_ctl *reset_ctl) +{ + debug("%s (%s): id %ld\n", + reset_ctl->dev->name, __func__, reset_ctl->id); + return 0; +} + +static int sunxi_reset_free(struct reset_ctl *reset_ctl) +{ + debug("%s (%s): id %ld\n", + reset_ctl->dev->name, __func__, reset_ctl->id); + return 0; +} + +static int sunxi_reset_update(struct reset_ctl *reset_ctl, bool assert) +{ + struct sunxi_reset_priv *priv = dev_get_priv(reset_ctl->dev); + unsigned long id = reset_ctl->id; + unsigned long offset = id / 32; /* TODO: symbolic name */ + unsigned int bit = id % 32; + + debug("%s (%s): id %ld base %p offset %lx bit %d assert %d size %ld\n", + reset_ctl->dev->name, __func__, id, priv->base, offset, + bit, assert, priv->size); + + if (offset >= priv->size) + return -EINVAL; + + if (assert) + clrbits_le32(priv->base + offset, BIT(bit)); + else + setbits_le32(priv->base + offset, BIT(bit)); + + return 0; +} + +static int sunxi_reset_assert(struct reset_ctl *reset_ctl) +{ + return sunxi_reset_update(reset_ctl, true); +} + +static int sunxi_reset_deassert(struct reset_ctl *reset_ctl) +{ + return sunxi_reset_update(reset_ctl, false); +} + +static const struct reset_ops sunxi_reset_ops = { + .request = sunxi_reset_request, + .free = sunxi_reset_free, + .rst_assert = sunxi_reset_assert, + .rst_deassert = sunxi_reset_deassert, +}; + +static int sunxi_reset_probe(struct udevice *dev) +{ + struct sunxi_reset_priv *priv = dev_get_priv(dev); + fdt_addr_t addr; + fdt_size_t size; + + addr = fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, dev->of_offset, + "reg", 0, &size, false); + if (addr == FDT_ADDR_T_NONE) { + debug("%s: failed to find base address ('reg')\n", dev->name); + return -ENODEV; + } + priv->base = (void *)addr; + priv->size = size; + + if (!priv->base) + return -ENOMEM; + + return 0; +} + +static const struct udevice_id sunxi_reset_match[] = { + { .compatible = "allwinner,sun6i-a31-clock-reset" }, + { } +}; + +U_BOOT_DRIVER(sunxi_reset) = { + .name = "sunxi-reset", + .id = UCLASS_RESET, + .of_match = sunxi_reset_match, + .ops = &sunxi_reset_ops, + .priv_auto_alloc_size = sizeof(struct sunxi_reset_priv), + .probe = sunxi_reset_probe, +};