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