xref: /qemu/hw/timer/mss-timer.c (revision 64552b6b)
1 /*
2  * Block model of System timer present in
3  * Microsemi's SmartFusion2 and SmartFusion SoCs.
4  *
5  * Copyright (c) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com>.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  */
25 
26 #include "qemu/osdep.h"
27 #include "qemu/main-loop.h"
28 #include "qemu/module.h"
29 #include "qemu/log.h"
30 #include "hw/irq.h"
31 #include "hw/timer/mss-timer.h"
32 
33 #ifndef MSS_TIMER_ERR_DEBUG
34 #define MSS_TIMER_ERR_DEBUG  0
35 #endif
36 
37 #define DB_PRINT_L(lvl, fmt, args...) do { \
38     if (MSS_TIMER_ERR_DEBUG >= lvl) { \
39         qemu_log("%s: " fmt "\n", __func__, ## args); \
40     } \
41 } while (0)
42 
43 #define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
44 
45 #define R_TIM_VAL         0
46 #define R_TIM_LOADVAL     1
47 #define R_TIM_BGLOADVAL   2
48 #define R_TIM_CTRL        3
49 #define R_TIM_RIS         4
50 #define R_TIM_MIS         5
51 
52 #define TIMER_CTRL_ENBL     (1 << 0)
53 #define TIMER_CTRL_ONESHOT  (1 << 1)
54 #define TIMER_CTRL_INTR     (1 << 2)
55 #define TIMER_RIS_ACK       (1 << 0)
56 #define TIMER_RST_CLR       (1 << 6)
57 #define TIMER_MODE          (1 << 0)
58 
59 static void timer_update_irq(struct Msf2Timer *st)
60 {
61     bool isr, ier;
62 
63     isr = !!(st->regs[R_TIM_RIS] & TIMER_RIS_ACK);
64     ier = !!(st->regs[R_TIM_CTRL] & TIMER_CTRL_INTR);
65     qemu_set_irq(st->irq, (ier && isr));
66 }
67 
68 static void timer_update(struct Msf2Timer *st)
69 {
70     uint64_t count;
71 
72     if (!(st->regs[R_TIM_CTRL] & TIMER_CTRL_ENBL)) {
73         ptimer_stop(st->ptimer);
74         return;
75     }
76 
77     count = st->regs[R_TIM_LOADVAL];
78     ptimer_set_limit(st->ptimer, count, 1);
79     ptimer_run(st->ptimer, 1);
80 }
81 
82 static uint64_t
83 timer_read(void *opaque, hwaddr offset, unsigned int size)
84 {
85     MSSTimerState *t = opaque;
86     hwaddr addr;
87     struct Msf2Timer *st;
88     uint32_t ret = 0;
89     int timer = 0;
90     int isr;
91     int ier;
92 
93     addr = offset >> 2;
94     /*
95      * Two independent timers has same base address.
96      * Based on address passed figure out which timer is being used.
97      */
98     if ((addr >= R_TIM1_MAX) && (addr < NUM_TIMERS * R_TIM1_MAX)) {
99         timer = 1;
100         addr -= R_TIM1_MAX;
101     }
102 
103     st = &t->timers[timer];
104 
105     switch (addr) {
106     case R_TIM_VAL:
107         ret = ptimer_get_count(st->ptimer);
108         break;
109 
110     case R_TIM_MIS:
111         isr = !!(st->regs[R_TIM_RIS] & TIMER_RIS_ACK);
112         ier = !!(st->regs[R_TIM_CTRL] & TIMER_CTRL_INTR);
113         ret = ier & isr;
114         break;
115 
116     default:
117         if (addr < R_TIM1_MAX) {
118             ret = st->regs[addr];
119         } else {
120             qemu_log_mask(LOG_GUEST_ERROR,
121                         TYPE_MSS_TIMER": 64-bit mode not supported\n");
122             return ret;
123         }
124         break;
125     }
126 
127     DB_PRINT("timer=%d 0x%" HWADDR_PRIx "=0x%" PRIx32, timer, offset,
128             ret);
129     return ret;
130 }
131 
132 static void
133 timer_write(void *opaque, hwaddr offset,
134             uint64_t val64, unsigned int size)
135 {
136     MSSTimerState *t = opaque;
137     hwaddr addr;
138     struct Msf2Timer *st;
139     int timer = 0;
140     uint32_t value = val64;
141 
142     addr = offset >> 2;
143     /*
144      * Two independent timers has same base address.
145      * Based on addr passed figure out which timer is being used.
146      */
147     if ((addr >= R_TIM1_MAX) && (addr < NUM_TIMERS * R_TIM1_MAX)) {
148         timer = 1;
149         addr -= R_TIM1_MAX;
150     }
151 
152     st = &t->timers[timer];
153 
154     DB_PRINT("addr=0x%" HWADDR_PRIx " val=0x%" PRIx32 " (timer=%d)", offset,
155             value, timer);
156 
157     switch (addr) {
158     case R_TIM_CTRL:
159         st->regs[R_TIM_CTRL] = value;
160         timer_update(st);
161         break;
162 
163     case R_TIM_RIS:
164         if (value & TIMER_RIS_ACK) {
165             st->regs[R_TIM_RIS] &= ~TIMER_RIS_ACK;
166         }
167         break;
168 
169     case R_TIM_LOADVAL:
170         st->regs[R_TIM_LOADVAL] = value;
171         if (st->regs[R_TIM_CTRL] & TIMER_CTRL_ENBL) {
172             timer_update(st);
173         }
174         break;
175 
176     case R_TIM_BGLOADVAL:
177         st->regs[R_TIM_BGLOADVAL] = value;
178         st->regs[R_TIM_LOADVAL] = value;
179         break;
180 
181     case R_TIM_VAL:
182     case R_TIM_MIS:
183         break;
184 
185     default:
186         if (addr < R_TIM1_MAX) {
187             st->regs[addr] = value;
188         } else {
189             qemu_log_mask(LOG_GUEST_ERROR,
190                         TYPE_MSS_TIMER": 64-bit mode not supported\n");
191             return;
192         }
193         break;
194     }
195     timer_update_irq(st);
196 }
197 
198 static const MemoryRegionOps timer_ops = {
199     .read = timer_read,
200     .write = timer_write,
201     .endianness = DEVICE_NATIVE_ENDIAN,
202     .valid = {
203         .min_access_size = 1,
204         .max_access_size = 4
205     }
206 };
207 
208 static void timer_hit(void *opaque)
209 {
210     struct Msf2Timer *st = opaque;
211 
212     st->regs[R_TIM_RIS] |= TIMER_RIS_ACK;
213 
214     if (!(st->regs[R_TIM_CTRL] & TIMER_CTRL_ONESHOT)) {
215         timer_update(st);
216     }
217     timer_update_irq(st);
218 }
219 
220 static void mss_timer_init(Object *obj)
221 {
222     MSSTimerState *t = MSS_TIMER(obj);
223     int i;
224 
225     /* Init all the ptimers.  */
226     for (i = 0; i < NUM_TIMERS; i++) {
227         struct Msf2Timer *st = &t->timers[i];
228 
229         st->bh = qemu_bh_new(timer_hit, st);
230         st->ptimer = ptimer_init(st->bh, PTIMER_POLICY_DEFAULT);
231         ptimer_set_freq(st->ptimer, t->freq_hz);
232         sysbus_init_irq(SYS_BUS_DEVICE(obj), &st->irq);
233     }
234 
235     memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t, TYPE_MSS_TIMER,
236                           NUM_TIMERS * R_TIM1_MAX * 4);
237     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &t->mmio);
238 }
239 
240 static const VMStateDescription vmstate_timers = {
241     .name = "mss-timer-block",
242     .version_id = 1,
243     .minimum_version_id = 1,
244     .fields = (VMStateField[]) {
245         VMSTATE_PTIMER(ptimer, struct Msf2Timer),
246         VMSTATE_UINT32_ARRAY(regs, struct Msf2Timer, R_TIM1_MAX),
247         VMSTATE_END_OF_LIST()
248     }
249 };
250 
251 static const VMStateDescription vmstate_mss_timer = {
252     .name = TYPE_MSS_TIMER,
253     .version_id = 1,
254     .minimum_version_id = 1,
255     .fields = (VMStateField[]) {
256         VMSTATE_UINT32(freq_hz, MSSTimerState),
257         VMSTATE_STRUCT_ARRAY(timers, MSSTimerState, NUM_TIMERS, 0,
258                 vmstate_timers, struct Msf2Timer),
259         VMSTATE_END_OF_LIST()
260     }
261 };
262 
263 static Property mss_timer_properties[] = {
264     /* Libero GUI shows 100Mhz as default for clocks */
265     DEFINE_PROP_UINT32("clock-frequency", MSSTimerState, freq_hz,
266                       100 * 1000000),
267     DEFINE_PROP_END_OF_LIST(),
268 };
269 
270 static void mss_timer_class_init(ObjectClass *klass, void *data)
271 {
272     DeviceClass *dc = DEVICE_CLASS(klass);
273 
274     dc->props = mss_timer_properties;
275     dc->vmsd = &vmstate_mss_timer;
276 }
277 
278 static const TypeInfo mss_timer_info = {
279     .name          = TYPE_MSS_TIMER,
280     .parent        = TYPE_SYS_BUS_DEVICE,
281     .instance_size = sizeof(MSSTimerState),
282     .instance_init = mss_timer_init,
283     .class_init    = mss_timer_class_init,
284 };
285 
286 static void mss_timer_register_types(void)
287 {
288     type_register_static(&mss_timer_info);
289 }
290 
291 type_init(mss_timer_register_types)
292