blob: d6bdf6bb00c4ac7808be49b2bc966ca42ad054bd [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
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
16struct jh7110_reset_priv {
17 void __iomem *reg;
18 u32 assert;
19 u32 status;
20 u32 resets;
21};
22
23struct reset_info {
24 const char *compat;
25 const u32 nr_resets;
26 const u32 assert_offset;
27 const u32 status_offset;
28};
29
30static 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
51static 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
62static 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
90static 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
99static 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
108static int jh7110_reset_free(struct reset_ctl *rst)
109{
110 return 0;
111}
112
113static 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
123static 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
145const 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
152U_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};