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