1 /*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2022-11-26 GuEe-GUI first version
9 */
10
11 #include "reset-simple.h"
12
13 struct reset_simple_data
14 {
15 rt_uint32_t reg_offset;
16 rt_bool_t active_low;
17 rt_bool_t status_active_low;
18 };
19
20 #define raw_to_reset_simple(raw) rt_container_of(raw, struct reset_simple, parent)
21
reset_simple_update(struct reset_simple * rsts,int id,rt_bool_t assert)22 static rt_err_t reset_simple_update(struct reset_simple *rsts, int id, rt_bool_t assert)
23 {
24 rt_uint32_t reg;
25 rt_ubase_t level;
26 int reg_width = sizeof(rt_uint32_t);
27 int bank = id / (reg_width * 8);
28 int offset = id % (reg_width * 8);
29
30 level = rt_spin_lock_irqsave(&rsts->lock);
31
32 reg = HWREG32(rsts->mmio_base + (bank * reg_width));
33
34 if (assert ^ rsts->active_low)
35 {
36 reg |= RT_BIT(offset);
37 }
38 else
39 {
40 reg &= ~RT_BIT(offset);
41 }
42
43 HWREG32(rsts->mmio_base + (bank * reg_width)) = reg;
44
45 rt_spin_unlock_irqrestore(&rsts->lock, level);
46
47 return RT_EOK;
48 }
49
reset_simple_assert(struct rt_reset_control * rstc)50 static rt_err_t reset_simple_assert(struct rt_reset_control *rstc)
51 {
52 struct reset_simple *rsts = raw_to_reset_simple(rstc);
53
54 return reset_simple_update(rsts, rstc->id, RT_TRUE);
55 }
56
reset_simple_deassert(struct rt_reset_control * rstc)57 static rt_err_t reset_simple_deassert(struct rt_reset_control *rstc)
58 {
59 struct reset_simple *rsts = raw_to_reset_simple(rstc);
60
61 return reset_simple_update(rsts, rstc->id, RT_FALSE);
62 }
63
reset_simple_reset(struct rt_reset_control * rstc)64 static rt_err_t reset_simple_reset(struct rt_reset_control *rstc)
65 {
66 rt_err_t err;
67 struct reset_simple *rsts = raw_to_reset_simple(rstc);
68
69 if (!rsts->reset_us)
70 {
71 return -RT_ENOSYS;
72 }
73
74 if ((err = reset_simple_assert(rstc)))
75 {
76 return err;
77 }
78
79 rt_hw_us_delay(rsts->reset_us + (rsts->reset_us >> 1));
80
81 return reset_simple_deassert(rstc);
82 }
83
reset_simple_status(struct rt_reset_control * rstc)84 static int reset_simple_status(struct rt_reset_control *rstc)
85 {
86 rt_uint32_t value;
87 int reg_width = sizeof(rt_uint32_t);
88 int bank = rstc->id / (reg_width * 8);
89 int offset = rstc->id % (reg_width * 8);
90 struct reset_simple *rsts = raw_to_reset_simple(rstc);
91
92 value = HWREG32(rsts->mmio_base + (bank * reg_width));
93
94 return !(value & RT_BIT(offset)) ^ !rsts->status_active_low;
95 }
96
97 const struct rt_reset_control_ops reset_simple_ops =
98 {
99 .reset = reset_simple_reset,
100 .assert = reset_simple_assert,
101 .deassert = reset_simple_deassert,
102 .status = reset_simple_status,
103 };
104
reset_simple_probe(struct rt_platform_device * pdev)105 static rt_err_t reset_simple_probe(struct rt_platform_device *pdev)
106 {
107 rt_err_t err;
108 struct rt_reset_controller *rstcer;
109 struct rt_device *dev = &pdev->parent;
110 const struct reset_simple_data *rsts_data = pdev->id->data;
111 struct reset_simple *rsts = rt_calloc(1, sizeof(*rsts));
112
113 if (!rsts)
114 {
115 return -RT_ENOMEM;
116 }
117
118 rsts->mmio_base = rt_dm_dev_iomap(dev, 0);
119
120 if (!rsts->mmio_base)
121 {
122 err = -RT_EIO;
123 goto _fail;
124 }
125
126 rt_spin_lock_init(&rsts->lock);
127
128 rstcer = &rsts->parent;
129
130 rstcer->priv = rsts;
131 rstcer->ofw_node = dev->ofw_node;
132 rstcer->ops = &reset_simple_ops;
133
134 if ((err = rt_reset_controller_register(rstcer)))
135 {
136 goto _fail;
137 }
138
139 if (rsts_data)
140 {
141 rsts->mmio_base += rsts_data->reg_offset;
142 rsts->active_low = rsts_data->active_low;
143 rsts->status_active_low = rsts_data->status_active_low;
144 }
145
146 return RT_EOK;
147
148 _fail:
149 if (rsts->mmio_base)
150 {
151 rt_iounmap(rsts->mmio_base);
152 }
153
154 rt_free(rsts);
155
156 return err;
157 }
158
159 static const struct reset_simple_data reset_simple_socfpga =
160 {
161 .reg_offset = 0x20,
162 .status_active_low = RT_TRUE,
163 };
164
165 static const struct reset_simple_data reset_simple_active_low =
166 {
167 .active_low = RT_TRUE,
168 .status_active_low = RT_TRUE,
169 };
170
171 static const struct rt_ofw_node_id reset_simple_ofw_ids[] =
172 {
173 { .compatible = "altr,stratix10-rst-mgr", .data = &reset_simple_socfpga },
174 { .compatible = "st,stm32-rcc", },
175 { .compatible = "allwinner,sun6i-a31-clock-reset", .data = &reset_simple_active_low },
176 { .compatible = "zte,zx296718-reset", .data = &reset_simple_active_low },
177 { .compatible = "aspeed,ast2400-lpc-reset" },
178 { .compatible = "aspeed,ast2500-lpc-reset" },
179 { .compatible = "aspeed,ast2600-lpc-reset" },
180 { .compatible = "bitmain,bm1880-reset", .data = &reset_simple_active_low },
181 { .compatible = "brcm,bcm4908-misc-pcie-reset", .data = &reset_simple_active_low },
182 { .compatible = "snps,dw-high-reset" },
183 { .compatible = "snps,dw-low-reset", .data = &reset_simple_active_low },
184 { .compatible = "sophgo,sg2042-reset", .data = &reset_simple_active_low },
185 { /* sentinel */ }
186 };
187
188 static struct rt_platform_driver reset_simple_driver =
189 {
190 .name = "reset-simple",
191 .ids = reset_simple_ofw_ids,
192
193 .probe = reset_simple_probe,
194 };
195
reset_simple_register(void)196 static int reset_simple_register(void)
197 {
198 rt_platform_driver_register(&reset_simple_driver);
199
200 return 0;
201 }
202 INIT_SUBSYS_EXPORT(reset_simple_register);
203