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 <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 
15 struct jh7110_reset_priv {
16 	void __iomem *reg;
17 	u32	assert;
18 	u32	status;
19 	u32	resets;
20 };
21 
22 struct reset_info {
23 	const char *compat;
24 	const u32 nr_resets;
25 	const u32 assert_offset;
26 	const u32 status_offset;
27 };
28 
29 static 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 
jh7110_reset_get_cfg(const char * compat)50 static 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 
jh7110_reset_trigger(struct jh7110_reset_priv * priv,unsigned long id,bool assert)61 static 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 
jh7110_reset_assert(struct reset_ctl * rst)89 static 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 
jh7110_reset_deassert(struct reset_ctl * rst)98 static 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 
jh7110_reset_free(struct reset_ctl * rst)107 static int jh7110_reset_free(struct reset_ctl *rst)
108 {
109 	return 0;
110 }
111 
jh7110_reset_request(struct reset_ctl * rst)112 static 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 
jh7110_reset_probe(struct udevice * dev)122 static 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 
144 const 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 
151 U_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 };
158