Statistics
| Branch: | Revision:

root / hw / timer / cadence_ttc.c @ f487b677

History | View | Annotate | Download (12.2 kB)

1 f3a6cc07 Peter A. G. Crosthwaite
/*
2 f3a6cc07 Peter A. G. Crosthwaite
 * Xilinx Zynq cadence TTC model
3 f3a6cc07 Peter A. G. Crosthwaite
 *
4 f3a6cc07 Peter A. G. Crosthwaite
 * Copyright (c) 2011 Xilinx Inc.
5 f3a6cc07 Peter A. G. Crosthwaite
 * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com)
6 f3a6cc07 Peter A. G. Crosthwaite
 * Copyright (c) 2012 PetaLogix Pty Ltd.
7 f3a6cc07 Peter A. G. Crosthwaite
 * Written By Haibing Ma
8 f3a6cc07 Peter A. G. Crosthwaite
 *            M. Habib
9 f3a6cc07 Peter A. G. Crosthwaite
 *
10 f3a6cc07 Peter A. G. Crosthwaite
 * This program is free software; you can redistribute it and/or
11 f3a6cc07 Peter A. G. Crosthwaite
 * modify it under the terms of the GNU General Public License
12 f3a6cc07 Peter A. G. Crosthwaite
 * as published by the Free Software Foundation; either version
13 f3a6cc07 Peter A. G. Crosthwaite
 * 2 of the License, or (at your option) any later version.
14 f3a6cc07 Peter A. G. Crosthwaite
 *
15 f3a6cc07 Peter A. G. Crosthwaite
 * You should have received a copy of the GNU General Public License along
16 f3a6cc07 Peter A. G. Crosthwaite
 * with this program; if not, see <http://www.gnu.org/licenses/>.
17 f3a6cc07 Peter A. G. Crosthwaite
 */
18 f3a6cc07 Peter A. G. Crosthwaite
19 83c9f4ca Paolo Bonzini
#include "hw/sysbus.h"
20 1de7afc9 Paolo Bonzini
#include "qemu/timer.h"
21 f3a6cc07 Peter A. G. Crosthwaite
22 f3a6cc07 Peter A. G. Crosthwaite
#ifdef CADENCE_TTC_ERR_DEBUG
23 f3a6cc07 Peter A. G. Crosthwaite
#define DB_PRINT(...) do { \
24 f3a6cc07 Peter A. G. Crosthwaite
    fprintf(stderr,  ": %s: ", __func__); \
25 f3a6cc07 Peter A. G. Crosthwaite
    fprintf(stderr, ## __VA_ARGS__); \
26 f3a6cc07 Peter A. G. Crosthwaite
    } while (0);
27 f3a6cc07 Peter A. G. Crosthwaite
#else
28 f3a6cc07 Peter A. G. Crosthwaite
    #define DB_PRINT(...)
29 f3a6cc07 Peter A. G. Crosthwaite
#endif
30 f3a6cc07 Peter A. G. Crosthwaite
31 f3a6cc07 Peter A. G. Crosthwaite
#define COUNTER_INTR_IV     0x00000001
32 f3a6cc07 Peter A. G. Crosthwaite
#define COUNTER_INTR_M1     0x00000002
33 f3a6cc07 Peter A. G. Crosthwaite
#define COUNTER_INTR_M2     0x00000004
34 f3a6cc07 Peter A. G. Crosthwaite
#define COUNTER_INTR_M3     0x00000008
35 f3a6cc07 Peter A. G. Crosthwaite
#define COUNTER_INTR_OV     0x00000010
36 f3a6cc07 Peter A. G. Crosthwaite
#define COUNTER_INTR_EV     0x00000020
37 f3a6cc07 Peter A. G. Crosthwaite
38 f3a6cc07 Peter A. G. Crosthwaite
#define COUNTER_CTRL_DIS    0x00000001
39 f3a6cc07 Peter A. G. Crosthwaite
#define COUNTER_CTRL_INT    0x00000002
40 f3a6cc07 Peter A. G. Crosthwaite
#define COUNTER_CTRL_DEC    0x00000004
41 f3a6cc07 Peter A. G. Crosthwaite
#define COUNTER_CTRL_MATCH  0x00000008
42 f3a6cc07 Peter A. G. Crosthwaite
#define COUNTER_CTRL_RST    0x00000010
43 f3a6cc07 Peter A. G. Crosthwaite
44 f3a6cc07 Peter A. G. Crosthwaite
#define CLOCK_CTRL_PS_EN    0x00000001
45 f3a6cc07 Peter A. G. Crosthwaite
#define CLOCK_CTRL_PS_V     0x0000001e
46 f3a6cc07 Peter A. G. Crosthwaite
47 f3a6cc07 Peter A. G. Crosthwaite
typedef struct {
48 f3a6cc07 Peter A. G. Crosthwaite
    QEMUTimer *timer;
49 f3a6cc07 Peter A. G. Crosthwaite
    int freq;
50 f3a6cc07 Peter A. G. Crosthwaite
51 f3a6cc07 Peter A. G. Crosthwaite
    uint32_t reg_clock;
52 f3a6cc07 Peter A. G. Crosthwaite
    uint32_t reg_count;
53 f3a6cc07 Peter A. G. Crosthwaite
    uint32_t reg_value;
54 f3a6cc07 Peter A. G. Crosthwaite
    uint16_t reg_interval;
55 f3a6cc07 Peter A. G. Crosthwaite
    uint16_t reg_match[3];
56 f3a6cc07 Peter A. G. Crosthwaite
    uint32_t reg_intr;
57 f3a6cc07 Peter A. G. Crosthwaite
    uint32_t reg_intr_en;
58 f3a6cc07 Peter A. G. Crosthwaite
    uint32_t reg_event_ctrl;
59 f3a6cc07 Peter A. G. Crosthwaite
    uint32_t reg_event;
60 f3a6cc07 Peter A. G. Crosthwaite
61 f3a6cc07 Peter A. G. Crosthwaite
    uint64_t cpu_time;
62 f3a6cc07 Peter A. G. Crosthwaite
    unsigned int cpu_time_valid;
63 f3a6cc07 Peter A. G. Crosthwaite
64 f3a6cc07 Peter A. G. Crosthwaite
    qemu_irq irq;
65 f3a6cc07 Peter A. G. Crosthwaite
} CadenceTimerState;
66 f3a6cc07 Peter A. G. Crosthwaite
67 f3a6cc07 Peter A. G. Crosthwaite
typedef struct {
68 f3a6cc07 Peter A. G. Crosthwaite
    SysBusDevice busdev;
69 f3a6cc07 Peter A. G. Crosthwaite
    MemoryRegion iomem;
70 f3a6cc07 Peter A. G. Crosthwaite
    CadenceTimerState timer[3];
71 f3a6cc07 Peter A. G. Crosthwaite
} CadenceTTCState;
72 f3a6cc07 Peter A. G. Crosthwaite
73 f3a6cc07 Peter A. G. Crosthwaite
static void cadence_timer_update(CadenceTimerState *s)
74 f3a6cc07 Peter A. G. Crosthwaite
{
75 f3a6cc07 Peter A. G. Crosthwaite
    qemu_set_irq(s->irq, !!(s->reg_intr & s->reg_intr_en));
76 f3a6cc07 Peter A. G. Crosthwaite
}
77 f3a6cc07 Peter A. G. Crosthwaite
78 f3a6cc07 Peter A. G. Crosthwaite
static CadenceTimerState *cadence_timer_from_addr(void *opaque,
79 a8170e5e Avi Kivity
                                        hwaddr offset)
80 f3a6cc07 Peter A. G. Crosthwaite
{
81 f3a6cc07 Peter A. G. Crosthwaite
    unsigned int index;
82 f3a6cc07 Peter A. G. Crosthwaite
    CadenceTTCState *s = (CadenceTTCState *)opaque;
83 f3a6cc07 Peter A. G. Crosthwaite
84 f3a6cc07 Peter A. G. Crosthwaite
    index = (offset >> 2) % 3;
85 f3a6cc07 Peter A. G. Crosthwaite
86 f3a6cc07 Peter A. G. Crosthwaite
    return &s->timer[index];
87 f3a6cc07 Peter A. G. Crosthwaite
}
88 f3a6cc07 Peter A. G. Crosthwaite
89 f3a6cc07 Peter A. G. Crosthwaite
static uint64_t cadence_timer_get_ns(CadenceTimerState *s, uint64_t timer_steps)
90 f3a6cc07 Peter A. G. Crosthwaite
{
91 f3a6cc07 Peter A. G. Crosthwaite
    /* timer_steps has max value of 0x100000000. double check it
92 f3a6cc07 Peter A. G. Crosthwaite
     * (or overflow can happen below) */
93 f3a6cc07 Peter A. G. Crosthwaite
    assert(timer_steps <= 1ULL << 32);
94 f3a6cc07 Peter A. G. Crosthwaite
95 f3a6cc07 Peter A. G. Crosthwaite
    uint64_t r = timer_steps * 1000000000ULL;
96 f3a6cc07 Peter A. G. Crosthwaite
    if (s->reg_clock & CLOCK_CTRL_PS_EN) {
97 f3a6cc07 Peter A. G. Crosthwaite
        r >>= 16 - (((s->reg_clock & CLOCK_CTRL_PS_V) >> 1) + 1);
98 f3a6cc07 Peter A. G. Crosthwaite
    } else {
99 f3a6cc07 Peter A. G. Crosthwaite
        r >>= 16;
100 f3a6cc07 Peter A. G. Crosthwaite
    }
101 f3a6cc07 Peter A. G. Crosthwaite
    r /= (uint64_t)s->freq;
102 f3a6cc07 Peter A. G. Crosthwaite
    return r;
103 f3a6cc07 Peter A. G. Crosthwaite
}
104 f3a6cc07 Peter A. G. Crosthwaite
105 f3a6cc07 Peter A. G. Crosthwaite
static uint64_t cadence_timer_get_steps(CadenceTimerState *s, uint64_t ns)
106 f3a6cc07 Peter A. G. Crosthwaite
{
107 f3a6cc07 Peter A. G. Crosthwaite
    uint64_t to_divide = 1000000000ULL;
108 f3a6cc07 Peter A. G. Crosthwaite
109 f3a6cc07 Peter A. G. Crosthwaite
    uint64_t r = ns;
110 f3a6cc07 Peter A. G. Crosthwaite
     /* for very large intervals (> 8s) do some division first to stop
111 f3a6cc07 Peter A. G. Crosthwaite
      * overflow (costs some prescision) */
112 f3a6cc07 Peter A. G. Crosthwaite
    while (r >= 8ULL << 30 && to_divide > 1) {
113 f3a6cc07 Peter A. G. Crosthwaite
        r /= 1000;
114 f3a6cc07 Peter A. G. Crosthwaite
        to_divide /= 1000;
115 f3a6cc07 Peter A. G. Crosthwaite
    }
116 f3a6cc07 Peter A. G. Crosthwaite
    r <<= 16;
117 f3a6cc07 Peter A. G. Crosthwaite
    /* keep early-dividing as needed */
118 f3a6cc07 Peter A. G. Crosthwaite
    while (r >= 8ULL << 30 && to_divide > 1) {
119 f3a6cc07 Peter A. G. Crosthwaite
        r /= 1000;
120 f3a6cc07 Peter A. G. Crosthwaite
        to_divide /= 1000;
121 f3a6cc07 Peter A. G. Crosthwaite
    }
122 f3a6cc07 Peter A. G. Crosthwaite
    r *= (uint64_t)s->freq;
123 f3a6cc07 Peter A. G. Crosthwaite
    if (s->reg_clock & CLOCK_CTRL_PS_EN) {
124 f3a6cc07 Peter A. G. Crosthwaite
        r /= 1 << (((s->reg_clock & CLOCK_CTRL_PS_V) >> 1) + 1);
125 f3a6cc07 Peter A. G. Crosthwaite
    }
126 f3a6cc07 Peter A. G. Crosthwaite
127 f3a6cc07 Peter A. G. Crosthwaite
    r /= to_divide;
128 f3a6cc07 Peter A. G. Crosthwaite
    return r;
129 f3a6cc07 Peter A. G. Crosthwaite
}
130 f3a6cc07 Peter A. G. Crosthwaite
131 f3a6cc07 Peter A. G. Crosthwaite
/* determine if x is in between a and b, exclusive of a, inclusive of b */
132 f3a6cc07 Peter A. G. Crosthwaite
133 f3a6cc07 Peter A. G. Crosthwaite
static inline int64_t is_between(int64_t x, int64_t a, int64_t b)
134 f3a6cc07 Peter A. G. Crosthwaite
{
135 f3a6cc07 Peter A. G. Crosthwaite
    if (a < b) {
136 f3a6cc07 Peter A. G. Crosthwaite
        return x > a && x <= b;
137 f3a6cc07 Peter A. G. Crosthwaite
    }
138 f3a6cc07 Peter A. G. Crosthwaite
    return x < a && x >= b;
139 f3a6cc07 Peter A. G. Crosthwaite
}
140 f3a6cc07 Peter A. G. Crosthwaite
141 f3a6cc07 Peter A. G. Crosthwaite
static void cadence_timer_run(CadenceTimerState *s)
142 f3a6cc07 Peter A. G. Crosthwaite
{
143 f3a6cc07 Peter A. G. Crosthwaite
    int i;
144 f3a6cc07 Peter A. G. Crosthwaite
    int64_t event_interval, next_value;
145 f3a6cc07 Peter A. G. Crosthwaite
146 f3a6cc07 Peter A. G. Crosthwaite
    assert(s->cpu_time_valid); /* cadence_timer_sync must be called first */
147 f3a6cc07 Peter A. G. Crosthwaite
148 f3a6cc07 Peter A. G. Crosthwaite
    if (s->reg_count & COUNTER_CTRL_DIS) {
149 f3a6cc07 Peter A. G. Crosthwaite
        s->cpu_time_valid = 0;
150 f3a6cc07 Peter A. G. Crosthwaite
        return;
151 f3a6cc07 Peter A. G. Crosthwaite
    }
152 f3a6cc07 Peter A. G. Crosthwaite
153 f3a6cc07 Peter A. G. Crosthwaite
    { /* figure out what's going to happen next (rollover or match) */
154 f3a6cc07 Peter A. G. Crosthwaite
        int64_t interval = (uint64_t)((s->reg_count & COUNTER_CTRL_INT) ?
155 f3a6cc07 Peter A. G. Crosthwaite
                (int64_t)s->reg_interval + 1 : 0x10000ULL) << 16;
156 f3a6cc07 Peter A. G. Crosthwaite
        next_value = (s->reg_count & COUNTER_CTRL_DEC) ? -1ULL : interval;
157 f3a6cc07 Peter A. G. Crosthwaite
        for (i = 0; i < 3; ++i) {
158 f3a6cc07 Peter A. G. Crosthwaite
            int64_t cand = (uint64_t)s->reg_match[i] << 16;
159 f3a6cc07 Peter A. G. Crosthwaite
            if (is_between(cand, (uint64_t)s->reg_value, next_value)) {
160 f3a6cc07 Peter A. G. Crosthwaite
                next_value = cand;
161 f3a6cc07 Peter A. G. Crosthwaite
            }
162 f3a6cc07 Peter A. G. Crosthwaite
        }
163 f3a6cc07 Peter A. G. Crosthwaite
    }
164 f3a6cc07 Peter A. G. Crosthwaite
    DB_PRINT("next timer event value: %09llx\n",
165 f3a6cc07 Peter A. G. Crosthwaite
            (unsigned long long)next_value);
166 f3a6cc07 Peter A. G. Crosthwaite
167 f3a6cc07 Peter A. G. Crosthwaite
    event_interval = next_value - (int64_t)s->reg_value;
168 f3a6cc07 Peter A. G. Crosthwaite
    event_interval = (event_interval < 0) ? -event_interval : event_interval;
169 f3a6cc07 Peter A. G. Crosthwaite
170 f3a6cc07 Peter A. G. Crosthwaite
    qemu_mod_timer(s->timer, s->cpu_time +
171 f3a6cc07 Peter A. G. Crosthwaite
                cadence_timer_get_ns(s, event_interval));
172 f3a6cc07 Peter A. G. Crosthwaite
}
173 f3a6cc07 Peter A. G. Crosthwaite
174 f3a6cc07 Peter A. G. Crosthwaite
static void cadence_timer_sync(CadenceTimerState *s)
175 f3a6cc07 Peter A. G. Crosthwaite
{
176 f3a6cc07 Peter A. G. Crosthwaite
    int i;
177 f3a6cc07 Peter A. G. Crosthwaite
    int64_t r, x;
178 f3a6cc07 Peter A. G. Crosthwaite
    int64_t interval = ((s->reg_count & COUNTER_CTRL_INT) ?
179 f3a6cc07 Peter A. G. Crosthwaite
            (int64_t)s->reg_interval + 1 : 0x10000ULL) << 16;
180 f3a6cc07 Peter A. G. Crosthwaite
    uint64_t old_time = s->cpu_time;
181 f3a6cc07 Peter A. G. Crosthwaite
182 f3a6cc07 Peter A. G. Crosthwaite
    s->cpu_time = qemu_get_clock_ns(vm_clock);
183 f3a6cc07 Peter A. G. Crosthwaite
    DB_PRINT("cpu time: %lld ns\n", (long long)old_time);
184 f3a6cc07 Peter A. G. Crosthwaite
185 f3a6cc07 Peter A. G. Crosthwaite
    if (!s->cpu_time_valid || old_time == s->cpu_time) {
186 f3a6cc07 Peter A. G. Crosthwaite
        s->cpu_time_valid = 1;
187 f3a6cc07 Peter A. G. Crosthwaite
        return;
188 f3a6cc07 Peter A. G. Crosthwaite
    }
189 f3a6cc07 Peter A. G. Crosthwaite
190 f3a6cc07 Peter A. G. Crosthwaite
    r = (int64_t)cadence_timer_get_steps(s, s->cpu_time - old_time);
191 f3a6cc07 Peter A. G. Crosthwaite
    x = (int64_t)s->reg_value + ((s->reg_count & COUNTER_CTRL_DEC) ? -r : r);
192 f3a6cc07 Peter A. G. Crosthwaite
193 f3a6cc07 Peter A. G. Crosthwaite
    for (i = 0; i < 3; ++i) {
194 f3a6cc07 Peter A. G. Crosthwaite
        int64_t m = (int64_t)s->reg_match[i] << 16;
195 f3a6cc07 Peter A. G. Crosthwaite
        if (m > interval) {
196 f3a6cc07 Peter A. G. Crosthwaite
            continue;
197 f3a6cc07 Peter A. G. Crosthwaite
        }
198 f3a6cc07 Peter A. G. Crosthwaite
        /* check to see if match event has occurred. check m +/- interval
199 f3a6cc07 Peter A. G. Crosthwaite
         * to account for match events in wrap around cases */
200 f3a6cc07 Peter A. G. Crosthwaite
        if (is_between(m, s->reg_value, x) ||
201 f3a6cc07 Peter A. G. Crosthwaite
            is_between(m + interval, s->reg_value, x) ||
202 f3a6cc07 Peter A. G. Crosthwaite
            is_between(m - interval, s->reg_value, x)) {
203 f3a6cc07 Peter A. G. Crosthwaite
            s->reg_intr |= (2 << i);
204 f3a6cc07 Peter A. G. Crosthwaite
        }
205 f3a6cc07 Peter A. G. Crosthwaite
    }
206 f3a6cc07 Peter A. G. Crosthwaite
    while (x < 0) {
207 f3a6cc07 Peter A. G. Crosthwaite
        x += interval;
208 f3a6cc07 Peter A. G. Crosthwaite
    }
209 f3a6cc07 Peter A. G. Crosthwaite
    s->reg_value = (uint32_t)(x % interval);
210 f3a6cc07 Peter A. G. Crosthwaite
211 f3a6cc07 Peter A. G. Crosthwaite
    if (s->reg_value != x) {
212 f3a6cc07 Peter A. G. Crosthwaite
        s->reg_intr |= (s->reg_count & COUNTER_CTRL_INT) ?
213 f3a6cc07 Peter A. G. Crosthwaite
            COUNTER_INTR_IV : COUNTER_INTR_OV;
214 f3a6cc07 Peter A. G. Crosthwaite
    }
215 f3a6cc07 Peter A. G. Crosthwaite
    cadence_timer_update(s);
216 f3a6cc07 Peter A. G. Crosthwaite
}
217 f3a6cc07 Peter A. G. Crosthwaite
218 f3a6cc07 Peter A. G. Crosthwaite
static void cadence_timer_tick(void *opaque)
219 f3a6cc07 Peter A. G. Crosthwaite
{
220 f3a6cc07 Peter A. G. Crosthwaite
    CadenceTimerState *s = opaque;
221 f3a6cc07 Peter A. G. Crosthwaite
222 f3a6cc07 Peter A. G. Crosthwaite
    DB_PRINT("\n");
223 f3a6cc07 Peter A. G. Crosthwaite
    cadence_timer_sync(s);
224 f3a6cc07 Peter A. G. Crosthwaite
    cadence_timer_run(s);
225 f3a6cc07 Peter A. G. Crosthwaite
}
226 f3a6cc07 Peter A. G. Crosthwaite
227 a8170e5e Avi Kivity
static uint32_t cadence_ttc_read_imp(void *opaque, hwaddr offset)
228 f3a6cc07 Peter A. G. Crosthwaite
{
229 f3a6cc07 Peter A. G. Crosthwaite
    CadenceTimerState *s = cadence_timer_from_addr(opaque, offset);
230 f3a6cc07 Peter A. G. Crosthwaite
    uint32_t value;
231 f3a6cc07 Peter A. G. Crosthwaite
232 f3a6cc07 Peter A. G. Crosthwaite
    cadence_timer_sync(s);
233 f3a6cc07 Peter A. G. Crosthwaite
    cadence_timer_run(s);
234 f3a6cc07 Peter A. G. Crosthwaite
235 f3a6cc07 Peter A. G. Crosthwaite
    switch (offset) {
236 f3a6cc07 Peter A. G. Crosthwaite
    case 0x00: /* clock control */
237 f3a6cc07 Peter A. G. Crosthwaite
    case 0x04:
238 f3a6cc07 Peter A. G. Crosthwaite
    case 0x08:
239 f3a6cc07 Peter A. G. Crosthwaite
        return s->reg_clock;
240 f3a6cc07 Peter A. G. Crosthwaite
241 f3a6cc07 Peter A. G. Crosthwaite
    case 0x0c: /* counter control */
242 f3a6cc07 Peter A. G. Crosthwaite
    case 0x10:
243 f3a6cc07 Peter A. G. Crosthwaite
    case 0x14:
244 f3a6cc07 Peter A. G. Crosthwaite
        return s->reg_count;
245 f3a6cc07 Peter A. G. Crosthwaite
246 f3a6cc07 Peter A. G. Crosthwaite
    case 0x18: /* counter value */
247 f3a6cc07 Peter A. G. Crosthwaite
    case 0x1c:
248 f3a6cc07 Peter A. G. Crosthwaite
    case 0x20:
249 f3a6cc07 Peter A. G. Crosthwaite
        return (uint16_t)(s->reg_value >> 16);
250 f3a6cc07 Peter A. G. Crosthwaite
251 f3a6cc07 Peter A. G. Crosthwaite
    case 0x24: /* reg_interval counter */
252 f3a6cc07 Peter A. G. Crosthwaite
    case 0x28:
253 f3a6cc07 Peter A. G. Crosthwaite
    case 0x2c:
254 f3a6cc07 Peter A. G. Crosthwaite
        return s->reg_interval;
255 f3a6cc07 Peter A. G. Crosthwaite
256 f3a6cc07 Peter A. G. Crosthwaite
    case 0x30: /* match 1 counter */
257 f3a6cc07 Peter A. G. Crosthwaite
    case 0x34:
258 f3a6cc07 Peter A. G. Crosthwaite
    case 0x38:
259 f3a6cc07 Peter A. G. Crosthwaite
        return s->reg_match[0];
260 f3a6cc07 Peter A. G. Crosthwaite
261 f3a6cc07 Peter A. G. Crosthwaite
    case 0x3c: /* match 2 counter */
262 f3a6cc07 Peter A. G. Crosthwaite
    case 0x40:
263 f3a6cc07 Peter A. G. Crosthwaite
    case 0x44:
264 f3a6cc07 Peter A. G. Crosthwaite
        return s->reg_match[1];
265 f3a6cc07 Peter A. G. Crosthwaite
266 f3a6cc07 Peter A. G. Crosthwaite
    case 0x48: /* match 3 counter */
267 f3a6cc07 Peter A. G. Crosthwaite
    case 0x4c:
268 f3a6cc07 Peter A. G. Crosthwaite
    case 0x50:
269 f3a6cc07 Peter A. G. Crosthwaite
        return s->reg_match[2];
270 f3a6cc07 Peter A. G. Crosthwaite
271 f3a6cc07 Peter A. G. Crosthwaite
    case 0x54: /* interrupt register */
272 f3a6cc07 Peter A. G. Crosthwaite
    case 0x58:
273 f3a6cc07 Peter A. G. Crosthwaite
    case 0x5c:
274 f3a6cc07 Peter A. G. Crosthwaite
        /* cleared after read */
275 f3a6cc07 Peter A. G. Crosthwaite
        value = s->reg_intr;
276 f3a6cc07 Peter A. G. Crosthwaite
        s->reg_intr = 0;
277 884285bf Soren Brinkmann
        cadence_timer_update(s);
278 f3a6cc07 Peter A. G. Crosthwaite
        return value;
279 f3a6cc07 Peter A. G. Crosthwaite
280 f3a6cc07 Peter A. G. Crosthwaite
    case 0x60: /* interrupt enable */
281 f3a6cc07 Peter A. G. Crosthwaite
    case 0x64:
282 f3a6cc07 Peter A. G. Crosthwaite
    case 0x68:
283 f3a6cc07 Peter A. G. Crosthwaite
        return s->reg_intr_en;
284 f3a6cc07 Peter A. G. Crosthwaite
285 f3a6cc07 Peter A. G. Crosthwaite
    case 0x6c:
286 f3a6cc07 Peter A. G. Crosthwaite
    case 0x70:
287 f3a6cc07 Peter A. G. Crosthwaite
    case 0x74:
288 f3a6cc07 Peter A. G. Crosthwaite
        return s->reg_event_ctrl;
289 f3a6cc07 Peter A. G. Crosthwaite
290 f3a6cc07 Peter A. G. Crosthwaite
    case 0x78:
291 f3a6cc07 Peter A. G. Crosthwaite
    case 0x7c:
292 f3a6cc07 Peter A. G. Crosthwaite
    case 0x80:
293 f3a6cc07 Peter A. G. Crosthwaite
        return s->reg_event;
294 f3a6cc07 Peter A. G. Crosthwaite
295 f3a6cc07 Peter A. G. Crosthwaite
    default:
296 f3a6cc07 Peter A. G. Crosthwaite
        return 0;
297 f3a6cc07 Peter A. G. Crosthwaite
    }
298 f3a6cc07 Peter A. G. Crosthwaite
}
299 f3a6cc07 Peter A. G. Crosthwaite
300 a8170e5e Avi Kivity
static uint64_t cadence_ttc_read(void *opaque, hwaddr offset,
301 f3a6cc07 Peter A. G. Crosthwaite
    unsigned size)
302 f3a6cc07 Peter A. G. Crosthwaite
{
303 f3a6cc07 Peter A. G. Crosthwaite
    uint32_t ret = cadence_ttc_read_imp(opaque, offset);
304 f3a6cc07 Peter A. G. Crosthwaite
305 c6954413 Peter Crosthwaite
    DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)ret);
306 f3a6cc07 Peter A. G. Crosthwaite
    return ret;
307 f3a6cc07 Peter A. G. Crosthwaite
}
308 f3a6cc07 Peter A. G. Crosthwaite
309 a8170e5e Avi Kivity
static void cadence_ttc_write(void *opaque, hwaddr offset,
310 f3a6cc07 Peter A. G. Crosthwaite
        uint64_t value, unsigned size)
311 f3a6cc07 Peter A. G. Crosthwaite
{
312 f3a6cc07 Peter A. G. Crosthwaite
    CadenceTimerState *s = cadence_timer_from_addr(opaque, offset);
313 f3a6cc07 Peter A. G. Crosthwaite
314 c6954413 Peter Crosthwaite
    DB_PRINT("addr: %08x data %08x\n", (unsigned)offset, (unsigned)value);
315 f3a6cc07 Peter A. G. Crosthwaite
316 f3a6cc07 Peter A. G. Crosthwaite
    cadence_timer_sync(s);
317 f3a6cc07 Peter A. G. Crosthwaite
318 f3a6cc07 Peter A. G. Crosthwaite
    switch (offset) {
319 f3a6cc07 Peter A. G. Crosthwaite
    case 0x00: /* clock control */
320 f3a6cc07 Peter A. G. Crosthwaite
    case 0x04:
321 f3a6cc07 Peter A. G. Crosthwaite
    case 0x08:
322 f3a6cc07 Peter A. G. Crosthwaite
        s->reg_clock = value & 0x3F;
323 f3a6cc07 Peter A. G. Crosthwaite
        break;
324 f3a6cc07 Peter A. G. Crosthwaite
325 f3a6cc07 Peter A. G. Crosthwaite
    case 0x0c: /* counter control */
326 f3a6cc07 Peter A. G. Crosthwaite
    case 0x10:
327 f3a6cc07 Peter A. G. Crosthwaite
    case 0x14:
328 f3a6cc07 Peter A. G. Crosthwaite
        if (value & COUNTER_CTRL_RST) {
329 f3a6cc07 Peter A. G. Crosthwaite
            s->reg_value = 0;
330 f3a6cc07 Peter A. G. Crosthwaite
        }
331 f3a6cc07 Peter A. G. Crosthwaite
        s->reg_count = value & 0x3f & ~COUNTER_CTRL_RST;
332 f3a6cc07 Peter A. G. Crosthwaite
        break;
333 f3a6cc07 Peter A. G. Crosthwaite
334 f3a6cc07 Peter A. G. Crosthwaite
    case 0x24: /* interval register */
335 f3a6cc07 Peter A. G. Crosthwaite
    case 0x28:
336 f3a6cc07 Peter A. G. Crosthwaite
    case 0x2c:
337 f3a6cc07 Peter A. G. Crosthwaite
        s->reg_interval = value & 0xffff;
338 f3a6cc07 Peter A. G. Crosthwaite
        break;
339 f3a6cc07 Peter A. G. Crosthwaite
340 f3a6cc07 Peter A. G. Crosthwaite
    case 0x30: /* match register */
341 f3a6cc07 Peter A. G. Crosthwaite
    case 0x34:
342 f3a6cc07 Peter A. G. Crosthwaite
    case 0x38:
343 f3a6cc07 Peter A. G. Crosthwaite
        s->reg_match[0] = value & 0xffff;
344 f3a6cc07 Peter A. G. Crosthwaite
345 f3a6cc07 Peter A. G. Crosthwaite
    case 0x3c: /* match register */
346 f3a6cc07 Peter A. G. Crosthwaite
    case 0x40:
347 f3a6cc07 Peter A. G. Crosthwaite
    case 0x44:
348 f3a6cc07 Peter A. G. Crosthwaite
        s->reg_match[1] = value & 0xffff;
349 f3a6cc07 Peter A. G. Crosthwaite
350 f3a6cc07 Peter A. G. Crosthwaite
    case 0x48: /* match register */
351 f3a6cc07 Peter A. G. Crosthwaite
    case 0x4c:
352 f3a6cc07 Peter A. G. Crosthwaite
    case 0x50:
353 f3a6cc07 Peter A. G. Crosthwaite
        s->reg_match[2] = value & 0xffff;
354 f3a6cc07 Peter A. G. Crosthwaite
        break;
355 f3a6cc07 Peter A. G. Crosthwaite
356 f3a6cc07 Peter A. G. Crosthwaite
    case 0x54: /* interrupt register */
357 f3a6cc07 Peter A. G. Crosthwaite
    case 0x58:
358 f3a6cc07 Peter A. G. Crosthwaite
    case 0x5c:
359 f3a6cc07 Peter A. G. Crosthwaite
        break;
360 f3a6cc07 Peter A. G. Crosthwaite
361 f3a6cc07 Peter A. G. Crosthwaite
    case 0x60: /* interrupt enable */
362 f3a6cc07 Peter A. G. Crosthwaite
    case 0x64:
363 f3a6cc07 Peter A. G. Crosthwaite
    case 0x68:
364 f3a6cc07 Peter A. G. Crosthwaite
        s->reg_intr_en = value & 0x3f;
365 f3a6cc07 Peter A. G. Crosthwaite
        break;
366 f3a6cc07 Peter A. G. Crosthwaite
367 f3a6cc07 Peter A. G. Crosthwaite
    case 0x6c: /* event control */
368 f3a6cc07 Peter A. G. Crosthwaite
    case 0x70:
369 f3a6cc07 Peter A. G. Crosthwaite
    case 0x74:
370 f3a6cc07 Peter A. G. Crosthwaite
        s->reg_event_ctrl = value & 0x07;
371 f3a6cc07 Peter A. G. Crosthwaite
        break;
372 f3a6cc07 Peter A. G. Crosthwaite
373 f3a6cc07 Peter A. G. Crosthwaite
    default:
374 f3a6cc07 Peter A. G. Crosthwaite
        return;
375 f3a6cc07 Peter A. G. Crosthwaite
    }
376 f3a6cc07 Peter A. G. Crosthwaite
377 f3a6cc07 Peter A. G. Crosthwaite
    cadence_timer_run(s);
378 f3a6cc07 Peter A. G. Crosthwaite
    cadence_timer_update(s);
379 f3a6cc07 Peter A. G. Crosthwaite
}
380 f3a6cc07 Peter A. G. Crosthwaite
381 f3a6cc07 Peter A. G. Crosthwaite
static const MemoryRegionOps cadence_ttc_ops = {
382 f3a6cc07 Peter A. G. Crosthwaite
    .read = cadence_ttc_read,
383 f3a6cc07 Peter A. G. Crosthwaite
    .write = cadence_ttc_write,
384 f3a6cc07 Peter A. G. Crosthwaite
    .endianness = DEVICE_NATIVE_ENDIAN,
385 f3a6cc07 Peter A. G. Crosthwaite
};
386 f3a6cc07 Peter A. G. Crosthwaite
387 f3a6cc07 Peter A. G. Crosthwaite
static void cadence_timer_reset(CadenceTimerState *s)
388 f3a6cc07 Peter A. G. Crosthwaite
{
389 f3a6cc07 Peter A. G. Crosthwaite
   s->reg_count = 0x21;
390 f3a6cc07 Peter A. G. Crosthwaite
}
391 f3a6cc07 Peter A. G. Crosthwaite
392 f3a6cc07 Peter A. G. Crosthwaite
static void cadence_timer_init(uint32_t freq, CadenceTimerState *s)
393 f3a6cc07 Peter A. G. Crosthwaite
{
394 f3a6cc07 Peter A. G. Crosthwaite
    memset(s, 0, sizeof(CadenceTimerState));
395 f3a6cc07 Peter A. G. Crosthwaite
    s->freq = freq;
396 f3a6cc07 Peter A. G. Crosthwaite
397 f3a6cc07 Peter A. G. Crosthwaite
    cadence_timer_reset(s);
398 f3a6cc07 Peter A. G. Crosthwaite
399 f3a6cc07 Peter A. G. Crosthwaite
    s->timer = qemu_new_timer_ns(vm_clock, cadence_timer_tick, s);
400 f3a6cc07 Peter A. G. Crosthwaite
}
401 f3a6cc07 Peter A. G. Crosthwaite
402 f3a6cc07 Peter A. G. Crosthwaite
static int cadence_ttc_init(SysBusDevice *dev)
403 f3a6cc07 Peter A. G. Crosthwaite
{
404 f3a6cc07 Peter A. G. Crosthwaite
    CadenceTTCState *s = FROM_SYSBUS(CadenceTTCState, dev);
405 f3a6cc07 Peter A. G. Crosthwaite
    int i;
406 f3a6cc07 Peter A. G. Crosthwaite
407 f3a6cc07 Peter A. G. Crosthwaite
    for (i = 0; i < 3; ++i) {
408 69efc026 Peter A. G. Crosthwaite
        cadence_timer_init(133000000, &s->timer[i]);
409 f3a6cc07 Peter A. G. Crosthwaite
        sysbus_init_irq(dev, &s->timer[i].irq);
410 f3a6cc07 Peter A. G. Crosthwaite
    }
411 f3a6cc07 Peter A. G. Crosthwaite
412 f3a6cc07 Peter A. G. Crosthwaite
    memory_region_init_io(&s->iomem, &cadence_ttc_ops, s, "timer", 0x1000);
413 f3a6cc07 Peter A. G. Crosthwaite
    sysbus_init_mmio(dev, &s->iomem);
414 f3a6cc07 Peter A. G. Crosthwaite
415 f3a6cc07 Peter A. G. Crosthwaite
    return 0;
416 f3a6cc07 Peter A. G. Crosthwaite
}
417 f3a6cc07 Peter A. G. Crosthwaite
418 f3a6cc07 Peter A. G. Crosthwaite
static void cadence_timer_pre_save(void *opaque)
419 f3a6cc07 Peter A. G. Crosthwaite
{
420 f3a6cc07 Peter A. G. Crosthwaite
    cadence_timer_sync((CadenceTimerState *)opaque);
421 f3a6cc07 Peter A. G. Crosthwaite
}
422 f3a6cc07 Peter A. G. Crosthwaite
423 f3a6cc07 Peter A. G. Crosthwaite
static int cadence_timer_post_load(void *opaque, int version_id)
424 f3a6cc07 Peter A. G. Crosthwaite
{
425 f3a6cc07 Peter A. G. Crosthwaite
    CadenceTimerState *s = opaque;
426 f3a6cc07 Peter A. G. Crosthwaite
427 f3a6cc07 Peter A. G. Crosthwaite
    s->cpu_time_valid = 0;
428 f3a6cc07 Peter A. G. Crosthwaite
    cadence_timer_sync(s);
429 f3a6cc07 Peter A. G. Crosthwaite
    cadence_timer_run(s);
430 f3a6cc07 Peter A. G. Crosthwaite
    cadence_timer_update(s);
431 f3a6cc07 Peter A. G. Crosthwaite
    return 0;
432 f3a6cc07 Peter A. G. Crosthwaite
}
433 f3a6cc07 Peter A. G. Crosthwaite
434 f3a6cc07 Peter A. G. Crosthwaite
static const VMStateDescription vmstate_cadence_timer = {
435 f3a6cc07 Peter A. G. Crosthwaite
    .name = "cadence_timer",
436 f3a6cc07 Peter A. G. Crosthwaite
    .version_id = 1,
437 f3a6cc07 Peter A. G. Crosthwaite
    .minimum_version_id = 1,
438 f3a6cc07 Peter A. G. Crosthwaite
    .minimum_version_id_old = 1,
439 f3a6cc07 Peter A. G. Crosthwaite
    .pre_save = cadence_timer_pre_save,
440 f3a6cc07 Peter A. G. Crosthwaite
    .post_load = cadence_timer_post_load,
441 f3a6cc07 Peter A. G. Crosthwaite
    .fields = (VMStateField[]) {
442 f3a6cc07 Peter A. G. Crosthwaite
        VMSTATE_UINT32(reg_clock, CadenceTimerState),
443 f3a6cc07 Peter A. G. Crosthwaite
        VMSTATE_UINT32(reg_count, CadenceTimerState),
444 f3a6cc07 Peter A. G. Crosthwaite
        VMSTATE_UINT32(reg_value, CadenceTimerState),
445 f3a6cc07 Peter A. G. Crosthwaite
        VMSTATE_UINT16(reg_interval, CadenceTimerState),
446 f3a6cc07 Peter A. G. Crosthwaite
        VMSTATE_UINT16_ARRAY(reg_match, CadenceTimerState, 3),
447 f3a6cc07 Peter A. G. Crosthwaite
        VMSTATE_UINT32(reg_intr, CadenceTimerState),
448 f3a6cc07 Peter A. G. Crosthwaite
        VMSTATE_UINT32(reg_intr_en, CadenceTimerState),
449 f3a6cc07 Peter A. G. Crosthwaite
        VMSTATE_UINT32(reg_event_ctrl, CadenceTimerState),
450 f3a6cc07 Peter A. G. Crosthwaite
        VMSTATE_UINT32(reg_event, CadenceTimerState),
451 f3a6cc07 Peter A. G. Crosthwaite
        VMSTATE_END_OF_LIST()
452 f3a6cc07 Peter A. G. Crosthwaite
    }
453 f3a6cc07 Peter A. G. Crosthwaite
};
454 f3a6cc07 Peter A. G. Crosthwaite
455 f3a6cc07 Peter A. G. Crosthwaite
static const VMStateDescription vmstate_cadence_ttc = {
456 f3a6cc07 Peter A. G. Crosthwaite
    .name = "cadence_TTC",
457 f3a6cc07 Peter A. G. Crosthwaite
    .version_id = 1,
458 f3a6cc07 Peter A. G. Crosthwaite
    .minimum_version_id = 1,
459 f3a6cc07 Peter A. G. Crosthwaite
    .minimum_version_id_old = 1,
460 f3a6cc07 Peter A. G. Crosthwaite
    .fields = (VMStateField[]) {
461 f3a6cc07 Peter A. G. Crosthwaite
        VMSTATE_STRUCT_ARRAY(timer, CadenceTTCState, 3, 0,
462 f3a6cc07 Peter A. G. Crosthwaite
                            vmstate_cadence_timer,
463 f3a6cc07 Peter A. G. Crosthwaite
                            CadenceTimerState),
464 f3a6cc07 Peter A. G. Crosthwaite
        VMSTATE_END_OF_LIST()
465 f3a6cc07 Peter A. G. Crosthwaite
    }
466 f3a6cc07 Peter A. G. Crosthwaite
};
467 f3a6cc07 Peter A. G. Crosthwaite
468 f3a6cc07 Peter A. G. Crosthwaite
static void cadence_ttc_class_init(ObjectClass *klass, void *data)
469 f3a6cc07 Peter A. G. Crosthwaite
{
470 f3a6cc07 Peter A. G. Crosthwaite
    DeviceClass *dc = DEVICE_CLASS(klass);
471 f3a6cc07 Peter A. G. Crosthwaite
    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
472 f3a6cc07 Peter A. G. Crosthwaite
473 f3a6cc07 Peter A. G. Crosthwaite
    sdc->init = cadence_ttc_init;
474 f3a6cc07 Peter A. G. Crosthwaite
    dc->vmsd = &vmstate_cadence_ttc;
475 f3a6cc07 Peter A. G. Crosthwaite
}
476 f3a6cc07 Peter A. G. Crosthwaite
477 8c43a6f0 Andreas Färber
static const TypeInfo cadence_ttc_info = {
478 f3a6cc07 Peter A. G. Crosthwaite
    .name  = "cadence_ttc",
479 f3a6cc07 Peter A. G. Crosthwaite
    .parent = TYPE_SYS_BUS_DEVICE,
480 f3a6cc07 Peter A. G. Crosthwaite
    .instance_size  = sizeof(CadenceTTCState),
481 f3a6cc07 Peter A. G. Crosthwaite
    .class_init = cadence_ttc_class_init,
482 f3a6cc07 Peter A. G. Crosthwaite
};
483 f3a6cc07 Peter A. G. Crosthwaite
484 f3a6cc07 Peter A. G. Crosthwaite
static void cadence_ttc_register_types(void)
485 f3a6cc07 Peter A. G. Crosthwaite
{
486 f3a6cc07 Peter A. G. Crosthwaite
    type_register_static(&cadence_ttc_info);
487 f3a6cc07 Peter A. G. Crosthwaite
}
488 f3a6cc07 Peter A. G. Crosthwaite
489 f3a6cc07 Peter A. G. Crosthwaite
type_init(cadence_ttc_register_types)