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