From 99ba4308701c51dcf425dbef42c6f87fcc9c42a2 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Fri, 18 Jan 2019 22:18:13 +0530 Subject: reset: Add Allwinner RESET driver Add common reset driver for all Allwinner SoC's. Since CLK and RESET share common DT compatible, it is CLK driver job is to bind the reset driver. So add CLK bind call on respective SoC driver by passing ccu map descriptor so-that reset deassert, deassert operations held based on ccu reset table defined from CLK driver. Select DM_RESET via CLK_SUNXI, this make hidden section of RESET since CLK and RESET share common DT compatible and code. Signed-off-by: Jagan Teki Acked-by: Maxime Ripard --- drivers/reset/Kconfig | 8 +++ drivers/reset/Makefile | 1 + drivers/reset/reset-sunxi.c | 124 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 drivers/reset/reset-sunxi.c (limited to 'drivers/reset') diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 3a6d61f440c..a81e7676960 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -113,4 +113,12 @@ config RESET_MEDIATEK help Support for reset controller on MediaTek SoCs. +config RESET_SUNXI + bool "RESET support for Allwinner SoCs" + depends on DM_RESET && ARCH_SUNXI + default y + help + This enables support for common reset driver for + Allwinner SoCs. + endmenu diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 8a4dcab8f64..4fad7d41298 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_RESET_ROCKCHIP) += reset-rockchip.o obj-$(CONFIG_RESET_MESON) += reset-meson.o obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_RESET_MEDIATEK) += reset-mediatek.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 00000000000..364dc52fb74 --- /dev/null +++ b/drivers/reset/reset-sunxi.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2018 Amarula Solutions. + * Author: Jagan Teki + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct sunxi_reset_priv { + void *base; + ulong count; + const struct ccu_desc *desc; +}; + +static const struct ccu_reset *priv_to_reset(struct sunxi_reset_priv *priv, + unsigned long id) +{ + return &priv->desc->resets[id]; +} + +static int sunxi_reset_request(struct reset_ctl *reset_ctl) +{ + struct sunxi_reset_priv *priv = dev_get_priv(reset_ctl->dev); + + debug("%s: (RST#%ld)\n", __func__, reset_ctl->id); + + if (reset_ctl->id >= priv->count) + return -EINVAL; + + return 0; +} + +static int sunxi_reset_free(struct reset_ctl *reset_ctl) +{ + debug("%s: (RST#%ld)\n", __func__, reset_ctl->id); + + return 0; +} + +static int sunxi_set_reset(struct reset_ctl *reset_ctl, bool on) +{ + struct sunxi_reset_priv *priv = dev_get_priv(reset_ctl->dev); + const struct ccu_reset *reset = priv_to_reset(priv, reset_ctl->id); + u32 reg; + + if (!(reset->flags & CCU_RST_F_IS_VALID)) { + printf("%s: (RST#%ld) unhandled\n", __func__, reset_ctl->id); + return 0; + } + + debug("%s: (RST#%ld) off#0x%x, BIT(%d)\n", __func__, + reset_ctl->id, reset->off, ilog2(reset->bit)); + + reg = readl(priv->base + reset->off); + if (on) + reg |= reset->bit; + else + reg &= ~reset->bit; + + writel(reg, priv->base + reset->off); + + return 0; +} + +static int sunxi_reset_assert(struct reset_ctl *reset_ctl) +{ + return sunxi_set_reset(reset_ctl, false); +} + +static int sunxi_reset_deassert(struct reset_ctl *reset_ctl) +{ + return sunxi_set_reset(reset_ctl, true); +} + +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); + + priv->base = dev_read_addr_ptr(dev); + + return 0; +} + +int sunxi_reset_bind(struct udevice *dev, ulong count) +{ + struct udevice *rst_dev; + struct sunxi_reset_priv *priv; + int ret; + + ret = device_bind_driver_to_node(dev, "sunxi_reset", "reset", + dev_ofnode(dev), &rst_dev); + if (ret) { + debug("failed to bind sunxi_reset driver (ret=%d)\n", ret); + return ret; + } + priv = malloc(sizeof(struct sunxi_reset_priv)); + priv->count = count; + priv->desc = (const struct ccu_desc *)dev_get_driver_data(dev); + rst_dev->priv = priv; + + return 0; +} + +U_BOOT_DRIVER(sunxi_reset) = { + .name = "sunxi_reset", + .id = UCLASS_RESET, + .ops = &sunxi_reset_ops, + .probe = sunxi_reset_probe, + .priv_auto_alloc_size = sizeof(struct sunxi_reset_priv), +}; -- cgit v1.2.3