blob: adf722d5871ad4a95d1588cb4e8518ef42d6ccdd [file] [log] [blame]
Yanhong Wangb417f062023-03-29 11:42:11 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2022 StarFive Technology Co., Ltd.
4 * Author: Yanhong Wang <yanhong.wang@starfivetech.com>
5 *
6 */
7
Yanhong Wangb417f062023-03-29 11:42:11 +08008#include <dm.h>
9#include <dm/ofnode.h>
10#include <dt-bindings/reset/starfive,jh7110-crg.h>
11#include <errno.h>
12#include <linux/iopoll.h>
13#include <reset-uclass.h>
14
15struct jh7110_reset_priv {
16 void __iomem *reg;
17 u32 assert;
18 u32 status;
19 u32 resets;
20};
21
22struct reset_info {
23 const char *compat;
24 const u32 nr_resets;
25 const u32 assert_offset;
26 const u32 status_offset;
27};
28
29static const struct reset_info jh7110_rst_info[] = {
30 {
31 .compat = "starfive,jh7110-syscrg",
32 .nr_resets = JH7110_SYSRST_END,
33 .assert_offset = 0x2F8,
34 .status_offset = 0x308,
35 },
36 {
37 .compat = "starfive,jh7110-aoncrg",
38 .nr_resets = JH7110_AONRST_END,
39 .assert_offset = 0x38,
40 .status_offset = 0x3C,
41 },
42 {
43 .compat = "starfive,jh7110-stgcrg",
44 .nr_resets = JH7110_STGRST_END,
45 .assert_offset = 0x74,
46 .status_offset = 0x78,
47 }
48};
49
50static const struct reset_info *jh7110_reset_get_cfg(const char *compat)
51{
52 int i;
53
54 for (i = 0; i < ARRAY_SIZE(jh7110_rst_info); i++)
55 if (!strcmp(compat, jh7110_rst_info[i].compat))
56 return &jh7110_rst_info[i];
57
58 return NULL;
59}
60
61static int jh7110_reset_trigger(struct jh7110_reset_priv *priv,
62 unsigned long id, bool assert)
63{
64 ulong group;
65 u32 mask, value, done = 0;
66 ulong addr;
67
68 group = id / 32;
69 mask = BIT(id % 32);
70
71 if (!assert)
72 done ^= mask;
73
74 addr = (ulong)priv->reg + priv->assert + group * sizeof(u32);
75 value = readl((ulong *)addr);
76
77 if (assert)
78 value |= mask;
79 else
80 value &= ~mask;
81
82 writel(value, (ulong *)addr);
83 addr = (ulong)priv->reg + priv->status + group * sizeof(u32);
84
85 return readl_poll_timeout((ulong *)addr, value,
86 (value & mask) == done, 1000);
87}
88
89static int jh7110_reset_assert(struct reset_ctl *rst)
90{
91 struct jh7110_reset_priv *priv = dev_get_priv(rst->dev);
92
93 jh7110_reset_trigger(priv, rst->id, true);
94
95 return 0;
96}
97
98static int jh7110_reset_deassert(struct reset_ctl *rst)
99{
100 struct jh7110_reset_priv *priv = dev_get_priv(rst->dev);
101
102 jh7110_reset_trigger(priv, rst->id, false);
103
104 return 0;
105}
106
107static int jh7110_reset_free(struct reset_ctl *rst)
108{
109 return 0;
110}
111
112static int jh7110_reset_request(struct reset_ctl *rst)
113{
114 struct jh7110_reset_priv *priv = dev_get_priv(rst->dev);
115
116 if (rst->id >= priv->resets)
117 return -EINVAL;
118
119 return 0;
120}
121
122static int jh7110_reset_probe(struct udevice *dev)
123{
124 struct jh7110_reset_priv *priv = dev_get_priv(dev);
125 const struct reset_info *cfg;
126 const char *compat;
127
128 compat = ofnode_get_property(dev_ofnode(dev), "compatible", NULL);
129 if (!compat)
130 return -EINVAL;
131
132 cfg = jh7110_reset_get_cfg(compat);
133 if (!cfg)
134 return -EINVAL;
135
136 priv->assert = cfg->assert_offset;
137 priv->status = cfg->status_offset;
138 priv->resets = cfg->nr_resets;
139 priv->reg = (void __iomem *)dev_read_addr_index(dev, 0);
140
141 return 0;
142}
143
144const struct reset_ops jh7110_reset_reset_ops = {
145 .rfree = jh7110_reset_free,
146 .request = jh7110_reset_request,
147 .rst_assert = jh7110_reset_assert,
148 .rst_deassert = jh7110_reset_deassert,
149};
150
151U_BOOT_DRIVER(jh7110_reset) = {
152 .name = "jh7110_reset",
153 .id = UCLASS_RESET,
154 .ops = &jh7110_reset_reset_ops,
155 .probe = jh7110_reset_probe,
156 .priv_auto = sizeof(struct jh7110_reset_priv),
157};