xref: /qemu/hw/timer/xilinx_timer.c (revision a630055df39e1960275d0e273af036f794b15662)
1 /*
2  * QEMU model of the Xilinx timer block.
3  *
4  * Copyright (c) 2009 Edgar E. Iglesias.
5  *
6  * DS573: https://docs.amd.com/v/u/en-US/xps_timer
7  * LogiCORE IP XPS Timer/Counter (v1.02a)
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a copy
10  * of this software and associated documentation files (the "Software"), to deal
11  * in the Software without restriction, including without limitation the rights
12  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13  * copies of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included in
17  * all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25  * THE SOFTWARE.
26  */
27 
28 #include "qemu/osdep.h"
29 #include "qapi/error.h"
30 #include "hw/sysbus.h"
31 #include "hw/irq.h"
32 #include "hw/ptimer.h"
33 #include "hw/qdev-properties.h"
34 #include "hw/qdev-properties-system.h"
35 #include "qemu/log.h"
36 #include "qemu/module.h"
37 #include "qom/object.h"
38 
39 #define D(x)
40 
41 #define R_TCSR     0
42 #define R_TLR      1
43 #define R_TCR      2
44 #define R_MAX      4
45 
46 #define TCSR_MDT        (1<<0)
47 #define TCSR_UDT        (1<<1)
48 #define TCSR_GENT       (1<<2)
49 #define TCSR_CAPT       (1<<3)
50 #define TCSR_ARHT       (1<<4)
51 #define TCSR_LOAD       (1<<5)
52 #define TCSR_ENIT       (1<<6)
53 #define TCSR_ENT        (1<<7)
54 #define TCSR_TINT       (1<<8)
55 #define TCSR_PWMA       (1<<9)
56 #define TCSR_ENALL      (1<<10)
57 
58 struct xlx_timer
59 {
60     ptimer_state *ptimer;
61     void *parent;
62     int nr; /* for debug.  */
63 
64     unsigned long timer_div;
65 
66     uint32_t regs[R_MAX];
67 };
68 
69 #define TYPE_XILINX_TIMER "xlnx.xps-timer"
70 typedef struct XpsTimerState XpsTimerState;
71 DECLARE_INSTANCE_CHECKER(XpsTimerState, XILINX_TIMER, TYPE_XILINX_TIMER)
72 
73 struct XpsTimerState
74 {
75     SysBusDevice parent_obj;
76 
77     EndianMode model_endianness;
78     MemoryRegion mmio;
79     qemu_irq irq;
80     uint8_t one_timer_only;
81     uint32_t freq_hz;
82     struct xlx_timer *timers;
83 };
84 
85 static inline unsigned int num_timers(XpsTimerState *t)
86 {
87     return 2 - t->one_timer_only;
88 }
89 
90 static inline unsigned int timer_from_addr(hwaddr addr)
91 {
92     /* Timers get a 4x32bit control reg area each.  */
93     return addr >> 2;
94 }
95 
96 static void timer_update_irq(XpsTimerState *t)
97 {
98     unsigned int i, irq = 0;
99     uint32_t csr;
100 
101     for (i = 0; i < num_timers(t); i++) {
102         csr = t->timers[i].regs[R_TCSR];
103         irq |= (csr & TCSR_TINT) && (csr & TCSR_ENIT);
104     }
105 
106     /* All timers within the same slave share a single IRQ line.  */
107     qemu_set_irq(t->irq, !!irq);
108 }
109 
110 static uint64_t
111 timer_read(void *opaque, hwaddr addr, unsigned int size)
112 {
113     XpsTimerState *t = opaque;
114     struct xlx_timer *xt;
115     uint32_t r = 0;
116     unsigned int timer;
117 
118     addr >>= 2;
119     timer = timer_from_addr(addr);
120     xt = &t->timers[timer];
121     /* Further decoding to address a specific timers reg.  */
122     addr &= 0x3;
123     switch (addr)
124     {
125         case R_TCR:
126                 r = ptimer_get_count(xt->ptimer);
127                 if (!(xt->regs[R_TCSR] & TCSR_UDT))
128                     r = ~r;
129                 D(qemu_log("xlx_timer t=%d read counter=%x udt=%d\n",
130                          timer, r, xt->regs[R_TCSR] & TCSR_UDT));
131             break;
132         default:
133             if (addr < ARRAY_SIZE(xt->regs))
134                 r = xt->regs[addr];
135             break;
136 
137     }
138     D(fprintf(stderr, "%s timer=%d %x=%x\n", __func__, timer, addr * 4, r));
139     return r;
140 }
141 
142 /* Must be called inside ptimer transaction block */
143 static void timer_enable(struct xlx_timer *xt)
144 {
145     uint64_t count;
146 
147     D(fprintf(stderr, "%s timer=%d down=%d\n", __func__,
148               xt->nr, xt->regs[R_TCSR] & TCSR_UDT));
149 
150     ptimer_stop(xt->ptimer);
151 
152     if (xt->regs[R_TCSR] & TCSR_UDT)
153         count = xt->regs[R_TLR];
154     else
155         count = ~0 - xt->regs[R_TLR];
156     ptimer_set_limit(xt->ptimer, count, 1);
157     ptimer_run(xt->ptimer, 1);
158 }
159 
160 static void
161 timer_write(void *opaque, hwaddr addr,
162             uint64_t val64, unsigned int size)
163 {
164     XpsTimerState *t = opaque;
165     struct xlx_timer *xt;
166     unsigned int timer;
167     uint32_t value = val64;
168 
169     addr >>= 2;
170     timer = timer_from_addr(addr);
171     xt = &t->timers[timer];
172     D(fprintf(stderr, "%s addr=%x val=%x (timer=%d off=%d)\n",
173              __func__, addr * 4, value, timer, addr & 3));
174     /* Further decoding to address a specific timers reg.  */
175     addr &= 3;
176     switch (addr)
177     {
178         case R_TCSR:
179             if (value & TCSR_TINT)
180                 value &= ~TCSR_TINT;
181 
182             xt->regs[addr] = value & 0x7ff;
183             if (value & TCSR_ENT) {
184                 ptimer_transaction_begin(xt->ptimer);
185                 timer_enable(xt);
186                 ptimer_transaction_commit(xt->ptimer);
187             }
188             break;
189 
190         default:
191             if (addr < ARRAY_SIZE(xt->regs))
192                 xt->regs[addr] = value;
193             break;
194     }
195     timer_update_irq(t);
196 }
197 
198 static const MemoryRegionOps timer_ops[2] = {
199     [0 ... 1] = {
200         .read = timer_read,
201         .write = timer_write,
202         .impl = {
203             .min_access_size = 4,
204             .max_access_size = 4,
205         },
206         .valid = {
207             .min_access_size = 4,
208             .max_access_size = 4,
209         },
210     },
211     [0].endianness = DEVICE_LITTLE_ENDIAN,
212     [1].endianness = DEVICE_BIG_ENDIAN,
213 };
214 
215 static void timer_hit(void *opaque)
216 {
217     struct xlx_timer *xt = opaque;
218     XpsTimerState *t = xt->parent;
219     D(fprintf(stderr, "%s %d\n", __func__, xt->nr));
220     xt->regs[R_TCSR] |= TCSR_TINT;
221 
222     if (xt->regs[R_TCSR] & TCSR_ARHT)
223         timer_enable(xt);
224     timer_update_irq(t);
225 }
226 
227 static void xilinx_timer_realize(DeviceState *dev, Error **errp)
228 {
229     XpsTimerState *t = XILINX_TIMER(dev);
230     unsigned int i;
231 
232     if (t->model_endianness == ENDIAN_MODE_UNSPECIFIED) {
233         error_setg(errp, TYPE_XILINX_TIMER " property 'endianness'"
234                          " must be set to 'big' or 'little'");
235         return;
236     }
237 
238     /* Init all the ptimers.  */
239     t->timers = g_malloc0(sizeof t->timers[0] * num_timers(t));
240     for (i = 0; i < num_timers(t); i++) {
241         struct xlx_timer *xt = &t->timers[i];
242 
243         xt->parent = t;
244         xt->nr = i;
245         xt->ptimer = ptimer_init(timer_hit, xt, PTIMER_POLICY_LEGACY);
246         ptimer_transaction_begin(xt->ptimer);
247         ptimer_set_freq(xt->ptimer, t->freq_hz);
248         ptimer_transaction_commit(xt->ptimer);
249     }
250 
251     memory_region_init_io(&t->mmio, OBJECT(t),
252                           &timer_ops[t->model_endianness == ENDIAN_MODE_BIG],
253                           t, "xlnx.xps-timer", R_MAX * 4 * num_timers(t));
254     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &t->mmio);
255 }
256 
257 static void xilinx_timer_init(Object *obj)
258 {
259     XpsTimerState *t = XILINX_TIMER(obj);
260 
261     /* All timers share a single irq line.  */
262     sysbus_init_irq(SYS_BUS_DEVICE(obj), &t->irq);
263 }
264 
265 static const Property xilinx_timer_properties[] = {
266     DEFINE_PROP_ENDIAN_NODEFAULT("endianness", XpsTimerState, model_endianness),
267     DEFINE_PROP_UINT32("clock-frequency", XpsTimerState, freq_hz, 62 * 1000000),
268     DEFINE_PROP_UINT8("one-timer-only", XpsTimerState, one_timer_only, 0),
269 };
270 
271 static void xilinx_timer_class_init(ObjectClass *klass, void *data)
272 {
273     DeviceClass *dc = DEVICE_CLASS(klass);
274 
275     dc->realize = xilinx_timer_realize;
276     device_class_set_props(dc, xilinx_timer_properties);
277 }
278 
279 static const TypeInfo xilinx_timer_info = {
280     .name          = TYPE_XILINX_TIMER,
281     .parent        = TYPE_SYS_BUS_DEVICE,
282     .instance_size = sizeof(XpsTimerState),
283     .instance_init = xilinx_timer_init,
284     .class_init    = xilinx_timer_class_init,
285 };
286 
287 static void xilinx_timer_register_types(void)
288 {
289     type_register_static(&xilinx_timer_info);
290 }
291 
292 type_init(xilinx_timer_register_types)
293