xref: /qemu/hw/misc/sifive_e_aon.c (revision bf01a04f5fbb4c22ac861a76fdc4c7a74247e44b)
1*bf01a04fSTommy Wu /*
2*bf01a04fSTommy Wu  * SiFive HiFive1 AON (Always On Domain) for QEMU.
3*bf01a04fSTommy Wu  *
4*bf01a04fSTommy Wu  * Copyright (c) 2022 SiFive, Inc. All rights reserved.
5*bf01a04fSTommy Wu  *
6*bf01a04fSTommy Wu  * This program is free software; you can redistribute it and/or modify it
7*bf01a04fSTommy Wu  * under the terms and conditions of the GNU General Public License,
8*bf01a04fSTommy Wu  * version 2 or later, as published by the Free Software Foundation.
9*bf01a04fSTommy Wu  *
10*bf01a04fSTommy Wu  * This program is distributed in the hope it will be useful, but WITHOUT
11*bf01a04fSTommy Wu  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12*bf01a04fSTommy Wu  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13*bf01a04fSTommy Wu  * more details.
14*bf01a04fSTommy Wu  *
15*bf01a04fSTommy Wu  * You should have received a copy of the GNU General Public License along with
16*bf01a04fSTommy Wu  * this program.  If not, see <http://www.gnu.org/licenses/>.
17*bf01a04fSTommy Wu  */
18*bf01a04fSTommy Wu 
19*bf01a04fSTommy Wu #include "qemu/osdep.h"
20*bf01a04fSTommy Wu #include "qemu/timer.h"
21*bf01a04fSTommy Wu #include "qemu/log.h"
22*bf01a04fSTommy Wu #include "hw/irq.h"
23*bf01a04fSTommy Wu #include "hw/registerfields.h"
24*bf01a04fSTommy Wu #include "hw/misc/sifive_e_aon.h"
25*bf01a04fSTommy Wu #include "qapi/visitor.h"
26*bf01a04fSTommy Wu #include "qapi/error.h"
27*bf01a04fSTommy Wu #include "sysemu/watchdog.h"
28*bf01a04fSTommy Wu #include "hw/qdev-properties.h"
29*bf01a04fSTommy Wu 
30*bf01a04fSTommy Wu REG32(AON_WDT_WDOGCFG, 0x0)
31*bf01a04fSTommy Wu     FIELD(AON_WDT_WDOGCFG, SCALE, 0, 4)
32*bf01a04fSTommy Wu     FIELD(AON_WDT_WDOGCFG, RSVD0, 4, 4)
33*bf01a04fSTommy Wu     FIELD(AON_WDT_WDOGCFG, RSTEN, 8, 1)
34*bf01a04fSTommy Wu     FIELD(AON_WDT_WDOGCFG, ZEROCMP, 9, 1)
35*bf01a04fSTommy Wu     FIELD(AON_WDT_WDOGCFG, RSVD1, 10, 2)
36*bf01a04fSTommy Wu     FIELD(AON_WDT_WDOGCFG, EN_ALWAYS, 12, 1)
37*bf01a04fSTommy Wu     FIELD(AON_WDT_WDOGCFG, EN_CORE_AWAKE, 13, 1)
38*bf01a04fSTommy Wu     FIELD(AON_WDT_WDOGCFG, RSVD2, 14, 14)
39*bf01a04fSTommy Wu     FIELD(AON_WDT_WDOGCFG, IP0, 28, 1)
40*bf01a04fSTommy Wu     FIELD(AON_WDT_WDOGCFG, RSVD3, 29, 3)
41*bf01a04fSTommy Wu REG32(AON_WDT_WDOGCOUNT, 0x8)
42*bf01a04fSTommy Wu     FIELD(AON_WDT_WDOGCOUNT, VALUE, 0, 31)
43*bf01a04fSTommy Wu REG32(AON_WDT_WDOGS, 0x10)
44*bf01a04fSTommy Wu REG32(AON_WDT_WDOGFEED, 0x18)
45*bf01a04fSTommy Wu REG32(AON_WDT_WDOGKEY, 0x1c)
46*bf01a04fSTommy Wu REG32(AON_WDT_WDOGCMP0, 0x20)
47*bf01a04fSTommy Wu 
48*bf01a04fSTommy Wu static void sifive_e_aon_wdt_update_wdogcount(SiFiveEAONState *r)
49*bf01a04fSTommy Wu {
50*bf01a04fSTommy Wu     int64_t now;
51*bf01a04fSTommy Wu     if (FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_ALWAYS) == 0 &&
52*bf01a04fSTommy Wu         FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE) == 0) {
53*bf01a04fSTommy Wu         return;
54*bf01a04fSTommy Wu     }
55*bf01a04fSTommy Wu 
56*bf01a04fSTommy Wu     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
57*bf01a04fSTommy Wu     r->wdogcount += muldiv64(now - r->wdog_restart_time,
58*bf01a04fSTommy Wu                              r->wdogclk_freq, NANOSECONDS_PER_SECOND);
59*bf01a04fSTommy Wu 
60*bf01a04fSTommy Wu     /* Clean the most significant bit. */
61*bf01a04fSTommy Wu     r->wdogcount &= R_AON_WDT_WDOGCOUNT_VALUE_MASK;
62*bf01a04fSTommy Wu     r->wdog_restart_time = now;
63*bf01a04fSTommy Wu }
64*bf01a04fSTommy Wu 
65*bf01a04fSTommy Wu static void sifive_e_aon_wdt_update_state(SiFiveEAONState *r)
66*bf01a04fSTommy Wu {
67*bf01a04fSTommy Wu     uint16_t wdogs;
68*bf01a04fSTommy Wu     bool cmp_signal = false;
69*bf01a04fSTommy Wu     sifive_e_aon_wdt_update_wdogcount(r);
70*bf01a04fSTommy Wu     wdogs = (uint16_t)(r->wdogcount >>
71*bf01a04fSTommy Wu                            FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, SCALE));
72*bf01a04fSTommy Wu 
73*bf01a04fSTommy Wu     if (wdogs >= r->wdogcmp0) {
74*bf01a04fSTommy Wu         cmp_signal = true;
75*bf01a04fSTommy Wu         if (FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, ZEROCMP) == 1) {
76*bf01a04fSTommy Wu             r->wdogcount = 0;
77*bf01a04fSTommy Wu             wdogs = 0;
78*bf01a04fSTommy Wu         }
79*bf01a04fSTommy Wu     }
80*bf01a04fSTommy Wu 
81*bf01a04fSTommy Wu     if (cmp_signal) {
82*bf01a04fSTommy Wu         if (FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, RSTEN) == 1) {
83*bf01a04fSTommy Wu             watchdog_perform_action();
84*bf01a04fSTommy Wu         }
85*bf01a04fSTommy Wu         r->wdogcfg = FIELD_DP32(r->wdogcfg, AON_WDT_WDOGCFG, IP0, 1);
86*bf01a04fSTommy Wu     }
87*bf01a04fSTommy Wu 
88*bf01a04fSTommy Wu     qemu_set_irq(r->wdog_irq, FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, IP0));
89*bf01a04fSTommy Wu 
90*bf01a04fSTommy Wu     if (wdogs < r->wdogcmp0 &&
91*bf01a04fSTommy Wu         (FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_ALWAYS) == 1 ||
92*bf01a04fSTommy Wu          FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE) == 1)) {
93*bf01a04fSTommy Wu         int64_t next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
94*bf01a04fSTommy Wu         next += muldiv64((r->wdogcmp0 - wdogs) <<
95*bf01a04fSTommy Wu                          FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, SCALE),
96*bf01a04fSTommy Wu                          NANOSECONDS_PER_SECOND, r->wdogclk_freq);
97*bf01a04fSTommy Wu         timer_mod(r->wdog_timer, next);
98*bf01a04fSTommy Wu     } else {
99*bf01a04fSTommy Wu         timer_mod(r->wdog_timer, INT64_MAX);
100*bf01a04fSTommy Wu     }
101*bf01a04fSTommy Wu }
102*bf01a04fSTommy Wu 
103*bf01a04fSTommy Wu /*
104*bf01a04fSTommy Wu  * Callback used when the timer set using timer_mod expires.
105*bf01a04fSTommy Wu  */
106*bf01a04fSTommy Wu static void sifive_e_aon_wdt_expired_cb(void *opaque)
107*bf01a04fSTommy Wu {
108*bf01a04fSTommy Wu     SiFiveEAONState *r = SIFIVE_E_AON(opaque);
109*bf01a04fSTommy Wu     sifive_e_aon_wdt_update_state(r);
110*bf01a04fSTommy Wu }
111*bf01a04fSTommy Wu 
112*bf01a04fSTommy Wu static uint64_t
113*bf01a04fSTommy Wu sifive_e_aon_wdt_read(void *opaque, hwaddr addr, unsigned int size)
114*bf01a04fSTommy Wu {
115*bf01a04fSTommy Wu     SiFiveEAONState *r = SIFIVE_E_AON(opaque);
116*bf01a04fSTommy Wu 
117*bf01a04fSTommy Wu     switch (addr) {
118*bf01a04fSTommy Wu     case A_AON_WDT_WDOGCFG:
119*bf01a04fSTommy Wu         return r->wdogcfg;
120*bf01a04fSTommy Wu     case A_AON_WDT_WDOGCOUNT:
121*bf01a04fSTommy Wu         sifive_e_aon_wdt_update_wdogcount(r);
122*bf01a04fSTommy Wu         return r->wdogcount;
123*bf01a04fSTommy Wu     case A_AON_WDT_WDOGS:
124*bf01a04fSTommy Wu         sifive_e_aon_wdt_update_wdogcount(r);
125*bf01a04fSTommy Wu         return r->wdogcount >>
126*bf01a04fSTommy Wu                FIELD_EX32(r->wdogcfg,
127*bf01a04fSTommy Wu                           AON_WDT_WDOGCFG,
128*bf01a04fSTommy Wu                           SCALE);
129*bf01a04fSTommy Wu     case A_AON_WDT_WDOGFEED:
130*bf01a04fSTommy Wu         return 0;
131*bf01a04fSTommy Wu     case A_AON_WDT_WDOGKEY:
132*bf01a04fSTommy Wu         return r->wdogunlock;
133*bf01a04fSTommy Wu     case A_AON_WDT_WDOGCMP0:
134*bf01a04fSTommy Wu         return r->wdogcmp0;
135*bf01a04fSTommy Wu     default:
136*bf01a04fSTommy Wu         qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read: addr=0x%x\n",
137*bf01a04fSTommy Wu                       __func__, (int)addr);
138*bf01a04fSTommy Wu     }
139*bf01a04fSTommy Wu 
140*bf01a04fSTommy Wu     return 0;
141*bf01a04fSTommy Wu }
142*bf01a04fSTommy Wu 
143*bf01a04fSTommy Wu static void
144*bf01a04fSTommy Wu sifive_e_aon_wdt_write(void *opaque, hwaddr addr,
145*bf01a04fSTommy Wu                        uint64_t val64, unsigned int size)
146*bf01a04fSTommy Wu {
147*bf01a04fSTommy Wu     SiFiveEAONState *r = SIFIVE_E_AON(opaque);
148*bf01a04fSTommy Wu     uint32_t value = val64;
149*bf01a04fSTommy Wu 
150*bf01a04fSTommy Wu     switch (addr) {
151*bf01a04fSTommy Wu     case A_AON_WDT_WDOGCFG: {
152*bf01a04fSTommy Wu         uint8_t new_en_always;
153*bf01a04fSTommy Wu         uint8_t new_en_core_awake;
154*bf01a04fSTommy Wu         uint8_t old_en_always;
155*bf01a04fSTommy Wu         uint8_t old_en_core_awake;
156*bf01a04fSTommy Wu         if (r->wdogunlock == 0) {
157*bf01a04fSTommy Wu             return;
158*bf01a04fSTommy Wu         }
159*bf01a04fSTommy Wu 
160*bf01a04fSTommy Wu         new_en_always = FIELD_EX32(value, AON_WDT_WDOGCFG, EN_ALWAYS);
161*bf01a04fSTommy Wu         new_en_core_awake = FIELD_EX32(value, AON_WDT_WDOGCFG, EN_CORE_AWAKE);
162*bf01a04fSTommy Wu         old_en_always = FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_ALWAYS);
163*bf01a04fSTommy Wu         old_en_core_awake = FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG,
164*bf01a04fSTommy Wu                                        EN_CORE_AWAKE);
165*bf01a04fSTommy Wu 
166*bf01a04fSTommy Wu         if ((old_en_always ||
167*bf01a04fSTommy Wu              old_en_core_awake) == 1 &&
168*bf01a04fSTommy Wu             (new_en_always ||
169*bf01a04fSTommy Wu              new_en_core_awake) == 0) {
170*bf01a04fSTommy Wu             sifive_e_aon_wdt_update_wdogcount(r);
171*bf01a04fSTommy Wu         } else if ((old_en_always ||
172*bf01a04fSTommy Wu                     old_en_core_awake) == 0 &&
173*bf01a04fSTommy Wu                    (new_en_always ||
174*bf01a04fSTommy Wu                     new_en_core_awake) == 1) {
175*bf01a04fSTommy Wu             r->wdog_restart_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
176*bf01a04fSTommy Wu         }
177*bf01a04fSTommy Wu         r->wdogcfg = value;
178*bf01a04fSTommy Wu         r->wdogunlock = 0;
179*bf01a04fSTommy Wu         break;
180*bf01a04fSTommy Wu     }
181*bf01a04fSTommy Wu     case A_AON_WDT_WDOGCOUNT:
182*bf01a04fSTommy Wu         if (r->wdogunlock == 0) {
183*bf01a04fSTommy Wu             return;
184*bf01a04fSTommy Wu         }
185*bf01a04fSTommy Wu         r->wdogcount = value & R_AON_WDT_WDOGCOUNT_VALUE_MASK;
186*bf01a04fSTommy Wu         r->wdog_restart_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
187*bf01a04fSTommy Wu         r->wdogunlock = 0;
188*bf01a04fSTommy Wu         break;
189*bf01a04fSTommy Wu     case A_AON_WDT_WDOGS:
190*bf01a04fSTommy Wu         return;
191*bf01a04fSTommy Wu     case A_AON_WDT_WDOGFEED:
192*bf01a04fSTommy Wu         if (r->wdogunlock == 0) {
193*bf01a04fSTommy Wu             return;
194*bf01a04fSTommy Wu         }
195*bf01a04fSTommy Wu         if (value == SIFIVE_E_AON_WDOGFEED) {
196*bf01a04fSTommy Wu             r->wdogcount = 0;
197*bf01a04fSTommy Wu             r->wdog_restart_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
198*bf01a04fSTommy Wu         }
199*bf01a04fSTommy Wu         r->wdogunlock = 0;
200*bf01a04fSTommy Wu         break;
201*bf01a04fSTommy Wu     case A_AON_WDT_WDOGKEY:
202*bf01a04fSTommy Wu         if (value == SIFIVE_E_AON_WDOGKEY) {
203*bf01a04fSTommy Wu             r->wdogunlock = 1;
204*bf01a04fSTommy Wu         }
205*bf01a04fSTommy Wu         break;
206*bf01a04fSTommy Wu     case A_AON_WDT_WDOGCMP0:
207*bf01a04fSTommy Wu         if (r->wdogunlock == 0) {
208*bf01a04fSTommy Wu             return;
209*bf01a04fSTommy Wu         }
210*bf01a04fSTommy Wu         r->wdogcmp0 = (uint16_t) value;
211*bf01a04fSTommy Wu         r->wdogunlock = 0;
212*bf01a04fSTommy Wu         break;
213*bf01a04fSTommy Wu     default:
214*bf01a04fSTommy Wu         qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%x v=0x%x\n",
215*bf01a04fSTommy Wu                       __func__, (int)addr, (int)value);
216*bf01a04fSTommy Wu     }
217*bf01a04fSTommy Wu     sifive_e_aon_wdt_update_state(r);
218*bf01a04fSTommy Wu }
219*bf01a04fSTommy Wu 
220*bf01a04fSTommy Wu static uint64_t
221*bf01a04fSTommy Wu sifive_e_aon_read(void *opaque, hwaddr addr, unsigned int size)
222*bf01a04fSTommy Wu {
223*bf01a04fSTommy Wu     if (addr < SIFIVE_E_AON_RTC) {
224*bf01a04fSTommy Wu         return sifive_e_aon_wdt_read(opaque, addr, size);
225*bf01a04fSTommy Wu     } else if (addr < SIFIVE_E_AON_MAX) {
226*bf01a04fSTommy Wu         qemu_log_mask(LOG_UNIMP, "%s: Unimplemented read: addr=0x%x\n",
227*bf01a04fSTommy Wu                       __func__, (int)addr);
228*bf01a04fSTommy Wu     } else {
229*bf01a04fSTommy Wu         qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read: addr=0x%x\n",
230*bf01a04fSTommy Wu                       __func__, (int)addr);
231*bf01a04fSTommy Wu     }
232*bf01a04fSTommy Wu     return 0;
233*bf01a04fSTommy Wu }
234*bf01a04fSTommy Wu 
235*bf01a04fSTommy Wu static void
236*bf01a04fSTommy Wu sifive_e_aon_write(void *opaque, hwaddr addr,
237*bf01a04fSTommy Wu                    uint64_t val64, unsigned int size)
238*bf01a04fSTommy Wu {
239*bf01a04fSTommy Wu     if (addr < SIFIVE_E_AON_RTC) {
240*bf01a04fSTommy Wu         sifive_e_aon_wdt_write(opaque, addr, val64, size);
241*bf01a04fSTommy Wu     } else if (addr < SIFIVE_E_AON_MAX) {
242*bf01a04fSTommy Wu         qemu_log_mask(LOG_UNIMP, "%s: Unimplemented write: addr=0x%x\n",
243*bf01a04fSTommy Wu                       __func__, (int)addr);
244*bf01a04fSTommy Wu     } else {
245*bf01a04fSTommy Wu         qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%x\n",
246*bf01a04fSTommy Wu                       __func__, (int)addr);
247*bf01a04fSTommy Wu     }
248*bf01a04fSTommy Wu }
249*bf01a04fSTommy Wu 
250*bf01a04fSTommy Wu static const MemoryRegionOps sifive_e_aon_ops = {
251*bf01a04fSTommy Wu     .read = sifive_e_aon_read,
252*bf01a04fSTommy Wu     .write = sifive_e_aon_write,
253*bf01a04fSTommy Wu     .endianness = DEVICE_NATIVE_ENDIAN,
254*bf01a04fSTommy Wu     .impl = {
255*bf01a04fSTommy Wu         .min_access_size = 4,
256*bf01a04fSTommy Wu         .max_access_size = 4
257*bf01a04fSTommy Wu     },
258*bf01a04fSTommy Wu     .valid = {
259*bf01a04fSTommy Wu         .min_access_size = 4,
260*bf01a04fSTommy Wu         .max_access_size = 4
261*bf01a04fSTommy Wu     }
262*bf01a04fSTommy Wu };
263*bf01a04fSTommy Wu 
264*bf01a04fSTommy Wu static void sifive_e_aon_reset(DeviceState *dev)
265*bf01a04fSTommy Wu {
266*bf01a04fSTommy Wu     SiFiveEAONState *r = SIFIVE_E_AON(dev);
267*bf01a04fSTommy Wu 
268*bf01a04fSTommy Wu     r->wdogcfg = FIELD_DP32(r->wdogcfg, AON_WDT_WDOGCFG, RSTEN, 0);
269*bf01a04fSTommy Wu     r->wdogcfg = FIELD_DP32(r->wdogcfg, AON_WDT_WDOGCFG, EN_ALWAYS, 0);
270*bf01a04fSTommy Wu     r->wdogcfg = FIELD_DP32(r->wdogcfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE, 0);
271*bf01a04fSTommy Wu     r->wdogcmp0 = 0xbeef;
272*bf01a04fSTommy Wu 
273*bf01a04fSTommy Wu     sifive_e_aon_wdt_update_state(r);
274*bf01a04fSTommy Wu }
275*bf01a04fSTommy Wu 
276*bf01a04fSTommy Wu static void sifive_e_aon_init(Object *obj)
277*bf01a04fSTommy Wu {
278*bf01a04fSTommy Wu     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
279*bf01a04fSTommy Wu     SiFiveEAONState *r = SIFIVE_E_AON(obj);
280*bf01a04fSTommy Wu 
281*bf01a04fSTommy Wu     memory_region_init_io(&r->mmio, OBJECT(r), &sifive_e_aon_ops, r,
282*bf01a04fSTommy Wu                           TYPE_SIFIVE_E_AON, SIFIVE_E_AON_MAX);
283*bf01a04fSTommy Wu     sysbus_init_mmio(sbd, &r->mmio);
284*bf01a04fSTommy Wu 
285*bf01a04fSTommy Wu     /* watchdog timer */
286*bf01a04fSTommy Wu     r->wdog_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
287*bf01a04fSTommy Wu                                  sifive_e_aon_wdt_expired_cb, r);
288*bf01a04fSTommy Wu     r->wdogclk_freq = SIFIVE_E_LFCLK_DEFAULT_FREQ;
289*bf01a04fSTommy Wu     sysbus_init_irq(sbd, &r->wdog_irq);
290*bf01a04fSTommy Wu }
291*bf01a04fSTommy Wu 
292*bf01a04fSTommy Wu static Property sifive_e_aon_properties[] = {
293*bf01a04fSTommy Wu     DEFINE_PROP_UINT64("wdogclk-frequency", SiFiveEAONState, wdogclk_freq,
294*bf01a04fSTommy Wu                        SIFIVE_E_LFCLK_DEFAULT_FREQ),
295*bf01a04fSTommy Wu     DEFINE_PROP_END_OF_LIST(),
296*bf01a04fSTommy Wu };
297*bf01a04fSTommy Wu 
298*bf01a04fSTommy Wu static void sifive_e_aon_class_init(ObjectClass *oc, void *data)
299*bf01a04fSTommy Wu {
300*bf01a04fSTommy Wu     DeviceClass *dc = DEVICE_CLASS(oc);
301*bf01a04fSTommy Wu 
302*bf01a04fSTommy Wu     dc->reset = sifive_e_aon_reset;
303*bf01a04fSTommy Wu     device_class_set_props(dc, sifive_e_aon_properties);
304*bf01a04fSTommy Wu }
305*bf01a04fSTommy Wu 
306*bf01a04fSTommy Wu static const TypeInfo sifive_e_aon_info = {
307*bf01a04fSTommy Wu     .name          = TYPE_SIFIVE_E_AON,
308*bf01a04fSTommy Wu     .parent        = TYPE_SYS_BUS_DEVICE,
309*bf01a04fSTommy Wu     .instance_size = sizeof(SiFiveEAONState),
310*bf01a04fSTommy Wu     .instance_init = sifive_e_aon_init,
311*bf01a04fSTommy Wu     .class_init    = sifive_e_aon_class_init,
312*bf01a04fSTommy Wu };
313*bf01a04fSTommy Wu 
314*bf01a04fSTommy Wu static void sifive_e_aon_register_types(void)
315*bf01a04fSTommy Wu {
316*bf01a04fSTommy Wu     type_register_static(&sifive_e_aon_info);
317*bf01a04fSTommy Wu }
318*bf01a04fSTommy Wu 
319*bf01a04fSTommy Wu type_init(sifive_e_aon_register_types)
320