Statistics
| Branch: | Revision:

root / hw / syborg_rtc.c @ df0db221

History | View | Annotate | Download (4 kB)

1
/*
2
 * Syborg RTC
3
 *
4
 * Copyright (c) 2008 CodeSourcery
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
#include "syborg.h"
28

    
29
enum {
30
    RTC_ID        = 0,
31
    RTC_LATCH     = 1,
32
    RTC_DATA_LOW  = 2,
33
    RTC_DATA_HIGH = 3
34
};
35

    
36
typedef struct {
37
    SysBusDevice busdev;
38
    int64_t offset;
39
    int64_t data;
40
    qemu_irq irq;
41
} SyborgRTCState;
42

    
43
static uint32_t syborg_rtc_read(void *opaque, target_phys_addr_t offset)
44
{
45
    SyborgRTCState *s = (SyborgRTCState *)opaque;
46
    offset &= 0xfff;
47
    switch (offset >> 2) {
48
    case RTC_ID:
49
        return SYBORG_ID_RTC;
50
    case RTC_DATA_LOW:
51
        return (uint32_t)s->data;
52
    case RTC_DATA_HIGH:
53
        return (uint32_t)(s->data >> 32);
54
    default:
55
        cpu_abort(cpu_single_env, "syborg_rtc_read: Bad offset %x\n",
56
                  (int)offset);
57
        return 0;
58
    }
59
}
60

    
61
static void syborg_rtc_write(void *opaque, target_phys_addr_t offset, uint32_t value)
62
{
63
    SyborgRTCState *s = (SyborgRTCState *)opaque;
64
    uint64_t now;
65

    
66
    offset &= 0xfff;
67
    switch (offset >> 2) {
68
    case RTC_LATCH:
69
        now = qemu_get_clock(vm_clock);
70
        if (value >= 4) {
71
            s->offset = s->data - now;
72
        } else {
73
            s->data = now + s->offset;
74
            while (value) {
75
                s->data /= 1000;
76
                value--;
77
            }
78
        }
79
        break;
80
    case RTC_DATA_LOW:
81
        s->data = (s->data & ~(uint64_t)0xffffffffu) | value;
82
        break;
83
    case RTC_DATA_HIGH:
84
        s->data = (s->data & 0xffffffffu) | ((uint64_t)value << 32);
85
        break;
86
    default:
87
        cpu_abort(cpu_single_env, "syborg_rtc_write: Bad offset %x\n",
88
                  (int)offset);
89
        break;
90
    }
91
}
92

    
93
static CPUReadMemoryFunc * const syborg_rtc_readfn[] = {
94
    syborg_rtc_read,
95
    syborg_rtc_read,
96
    syborg_rtc_read
97
};
98

    
99
static CPUWriteMemoryFunc * const syborg_rtc_writefn[] = {
100
    syborg_rtc_write,
101
    syborg_rtc_write,
102
    syborg_rtc_write
103
};
104

    
105
static void syborg_rtc_save(QEMUFile *f, void *opaque)
106
{
107
    SyborgRTCState *s = opaque;
108

    
109
    qemu_put_be64(f, s->offset);
110
    qemu_put_be64(f, s->data);
111
}
112

    
113
static int syborg_rtc_load(QEMUFile *f, void *opaque, int version_id)
114
{
115
    SyborgRTCState *s = opaque;
116

    
117
    if (version_id != 1)
118
        return -EINVAL;
119

    
120
    s->offset = qemu_get_be64(f);
121
    s->data = qemu_get_be64(f);
122

    
123
    return 0;
124
}
125

    
126
static int syborg_rtc_init(SysBusDevice *dev)
127
{
128
    SyborgRTCState *s = FROM_SYSBUS(SyborgRTCState, dev);
129
    struct tm tm;
130
    int iomemtype;
131

    
132
    iomemtype = cpu_register_io_memory(syborg_rtc_readfn,
133
                                       syborg_rtc_writefn, s);
134
    sysbus_init_mmio(dev, 0x1000, iomemtype);
135

    
136
    qemu_get_timedate(&tm, 0);
137
    s->offset = (uint64_t)mktime(&tm) * 1000000000;
138

    
139
    register_savevm(&dev->qdev, "syborg_rtc", -1, 1,
140
                    syborg_rtc_save, syborg_rtc_load, s);
141
    return 0;
142
}
143

    
144
static void syborg_rtc_register_devices(void)
145
{
146
    sysbus_register_dev("syborg,rtc", sizeof(SyborgRTCState), syborg_rtc_init);
147
}
148

    
149
device_init(syborg_rtc_register_devices)