Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2020 Sifive, Inc. * Author: Sagar Kadam <sagar.kadam@sifive.com> */ #include <dm.h> #include <reset-uclass.h> #include <asm/io.h> #include <dm/device_compat.h> #include <dm/device-internal.h> #include <dm/lists.h> #include <linux/bitops.h> #define PRCI_RESETREG_OFFSET 0x28 struct sifive_reset_priv { void *base; /* number of reset signals */ int nr_reset; }; static int sifive_rst_trigger(struct reset_ctl *rst, bool level) { struct sifive_reset_priv *priv = dev_get_priv(rst->dev); int id = rst->id; int regval = readl(priv->base + PRCI_RESETREG_OFFSET); /* Derive bitposition from rst id */ if (level) /* Reset deassert */ regval |= BIT(id); else /* Reset assert */ regval &= ~BIT(id); writel(regval, priv->base + PRCI_RESETREG_OFFSET); return 0; } static int sifive_reset_assert(struct reset_ctl *rst) { return sifive_rst_trigger(rst, false); } static int sifive_reset_deassert(struct reset_ctl *rst) { return sifive_rst_trigger(rst, true); } static int sifive_reset_request(struct reset_ctl *rst) { struct sifive_reset_priv *priv = dev_get_priv(rst->dev); debug("%s(rst=%p) (dev=%p, id=%lu) (nr_reset=%d)\n", __func__, rst, rst->dev, rst->id, priv->nr_reset); if (rst->id > priv->nr_reset) return -EINVAL; return 0; } static int sifive_reset_probe(struct udevice *dev) { struct sifive_reset_priv *priv = dev_get_priv(dev); priv->base = dev_remap_addr(dev); if (!priv->base) return -ENOMEM; return 0; } int sifive_reset_bind(struct udevice *dev, ulong count) { struct udevice *rst_dev; struct sifive_reset_priv *priv; int ret; ret = device_bind_driver_to_node(dev, "sifive-reset", "reset", dev_ofnode(dev), &rst_dev); if (ret) { dev_err(dev, "failed to bind sifive_reset driver (ret=%d)\n", ret); return ret; } priv = malloc(sizeof(struct sifive_reset_priv)); priv->nr_reset = count; dev_set_priv(rst_dev, priv); return 0; } const struct reset_ops sifive_reset_ops = { .request = sifive_reset_request, .rst_assert = sifive_reset_assert, .rst_deassert = sifive_reset_deassert, }; U_BOOT_DRIVER(sifive_reset) = { .name = "sifive-reset", .id = UCLASS_RESET, .ops = &sifive_reset_ops, .probe = sifive_reset_probe, .priv_auto = sizeof(struct sifive_reset_priv), }; |