Statistics
| Branch: | Revision:

root / hw / xilinx_timer.c @ ae60fea9

History | View | Annotate | Download (6.2 kB)

1
/*
2
 * QEMU model of the Xilinx timer block.
3
 *
4
 * Copyright (c) 2009 Edgar E. Iglesias.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24

    
25
#include "sysbus.h"
26
#include "qemu-timer.h"
27

    
28
#define D(x)
29

    
30
#define R_TCSR     0
31
#define R_TLR      1
32
#define R_TCR      2
33
#define R_MAX      4
34

    
35
#define TCSR_MDT        (1<<0)
36
#define TCSR_UDT        (1<<1)
37
#define TCSR_GENT       (1<<2)
38
#define TCSR_CAPT       (1<<3)
39
#define TCSR_ARHT       (1<<4)
40
#define TCSR_LOAD       (1<<5)
41
#define TCSR_ENIT       (1<<6)
42
#define TCSR_ENT        (1<<7)
43
#define TCSR_TINT       (1<<8)
44
#define TCSR_PWMA       (1<<9)
45
#define TCSR_ENALL      (1<<10)
46

    
47
struct xlx_timer
48
{
49
    QEMUBH *bh;
50
    ptimer_state *ptimer;
51
    void *parent;
52
    int nr; /* for debug.  */
53

    
54
    unsigned long timer_div;
55

    
56
    uint32_t regs[R_MAX];
57
};
58

    
59
struct timerblock
60
{
61
    SysBusDevice busdev;
62
    qemu_irq irq;
63
    uint32_t nr_timers;
64
    uint32_t freq_hz;
65
    struct xlx_timer *timers;
66
};
67

    
68
static inline unsigned int timer_from_addr(target_phys_addr_t addr)
69
{
70
    /* Timers get a 4x32bit control reg area each.  */
71
    return addr >> 2;
72
}
73

    
74
static void timer_update_irq(struct timerblock *t)
75
{
76
    unsigned int i, irq = 0;
77
    uint32_t csr;
78

    
79
    for (i = 0; i < t->nr_timers; i++) {
80
        csr = t->timers[i].regs[R_TCSR];
81
        irq |= (csr & TCSR_TINT) && (csr & TCSR_ENIT);
82
    }
83

    
84
    /* All timers within the same slave share a single IRQ line.  */
85
    qemu_set_irq(t->irq, !!irq);
86
}
87

    
88
static uint32_t timer_readl (void *opaque, target_phys_addr_t addr)
89
{
90
    struct timerblock *t = opaque;
91
    struct xlx_timer *xt;
92
    uint32_t r = 0;
93
    unsigned int timer;
94

    
95
    addr >>= 2;
96
    timer = timer_from_addr(addr);
97
    xt = &t->timers[timer];
98
    /* Further decoding to address a specific timers reg.  */
99
    addr &= 0x3;
100
    switch (addr)
101
    {
102
        case R_TCR:
103
                r = ptimer_get_count(xt->ptimer);
104
                if (!(xt->regs[R_TCSR] & TCSR_UDT))
105
                    r = ~r;
106
                D(qemu_log("xlx_timer t=%d read counter=%x udt=%d\n",
107
                         timer, r, xt->regs[R_TCSR] & TCSR_UDT));
108
            break;
109
        default:
110
            if (addr < ARRAY_SIZE(xt->regs))
111
                r = xt->regs[addr];
112
            break;
113

    
114
    }
115
    D(printf("%s timer=%d %x=%x\n", __func__, timer, addr * 4, r));
116
    return r;
117
}
118

    
119
static void timer_enable(struct xlx_timer *xt)
120
{
121
    uint64_t count;
122

    
123
    D(printf("%s timer=%d down=%d\n", __func__,
124
              xt->nr, xt->regs[R_TCSR] & TCSR_UDT));
125

    
126
    ptimer_stop(xt->ptimer);
127

    
128
    if (xt->regs[R_TCSR] & TCSR_UDT)
129
        count = xt->regs[R_TLR];
130
    else
131
        count = ~0 - xt->regs[R_TLR];
132
    ptimer_set_count(xt->ptimer, count);
133
    ptimer_run(xt->ptimer, 1);
134
}
135

    
136
static void
137
timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
138
{
139
    struct timerblock *t = opaque;
140
    struct xlx_timer *xt;
141
    unsigned int timer;
142

    
143
    addr >>= 2;
144
    timer = timer_from_addr(addr);
145
    xt = &t->timers[timer];
146
    D(printf("%s addr=%x val=%x (timer=%d off=%d)\n",
147
             __func__, addr * 4, value, timer, addr & 3));
148
    /* Further decoding to address a specific timers reg.  */
149
    addr &= 3;
150
    switch (addr) 
151
    {
152
        case R_TCSR:
153
            if (value & TCSR_TINT)
154
                value &= ~TCSR_TINT;
155

    
156
            xt->regs[addr] = value;
157
            if (value & TCSR_ENT)
158
                timer_enable(xt);
159
            break;
160
 
161
        default:
162
            if (addr < ARRAY_SIZE(xt->regs))
163
                xt->regs[addr] = value;
164
            break;
165
    }
166
    timer_update_irq(t);
167
}
168

    
169
static CPUReadMemoryFunc * const timer_read[] = {
170
    NULL, NULL,
171
    &timer_readl,
172
};
173

    
174
static CPUWriteMemoryFunc * const timer_write[] = {
175
    NULL, NULL,
176
    &timer_writel,
177
};
178

    
179
static void timer_hit(void *opaque)
180
{
181
    struct xlx_timer *xt = opaque;
182
    struct timerblock *t = xt->parent;
183
    D(printf("%s %d\n", __func__, timer));
184
    xt->regs[R_TCSR] |= TCSR_TINT;
185

    
186
    if (xt->regs[R_TCSR] & TCSR_ARHT)
187
        timer_enable(xt);
188
    timer_update_irq(t);
189
}
190

    
191
static int xilinx_timer_init(SysBusDevice *dev)
192
{
193
    struct timerblock *t = FROM_SYSBUS(typeof (*t), dev);
194
    unsigned int i;
195
    int timer_regs;
196

    
197
    /* All timers share a single irq line.  */
198
    sysbus_init_irq(dev, &t->irq);
199

    
200
    /* Init all the ptimers.  */
201
    t->timers = qemu_mallocz(sizeof t->timers[0] * t->nr_timers);
202
    for (i = 0; i < t->nr_timers; i++) {
203
        struct xlx_timer *xt = &t->timers[i];
204

    
205
        xt->parent = t;
206
        xt->nr = i;
207
        xt->bh = qemu_bh_new(timer_hit, xt);
208
        xt->ptimer = ptimer_init(xt->bh);
209
        ptimer_set_freq(xt->ptimer, t->freq_hz);
210
    }
211

    
212
    timer_regs = cpu_register_io_memory(timer_read, timer_write, t,
213
                                        DEVICE_NATIVE_ENDIAN);
214
    sysbus_init_mmio(dev, R_MAX * 4 * t->nr_timers, timer_regs);
215
    return 0;
216
}
217

    
218
static SysBusDeviceInfo xilinx_timer_info = {
219
    .init = xilinx_timer_init,
220
    .qdev.name  = "xilinx,timer",
221
    .qdev.size  = sizeof(struct timerblock),
222
    .qdev.props = (Property[]) {
223
        DEFINE_PROP_UINT32("frequency", struct timerblock, freq_hz,   0),
224
        DEFINE_PROP_UINT32("nr-timers", struct timerblock, nr_timers, 0),
225
        DEFINE_PROP_END_OF_LIST(),
226
    }
227
};
228

    
229
static void xilinx_timer_register(void)
230
{
231
    sysbus_register_withprop(&xilinx_timer_info);
232
}
233

    
234
device_init(xilinx_timer_register)