Statistics
| Branch: | Revision:

root / hw / char / digic-uart.c @ 142593c9

History | View | Annotate | Download (4.7 kB)

1
/*
2
 * QEMU model of the Canon DIGIC UART block.
3
 *
4
 * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com>
5
 *
6
 * This model is based on reverse engineering efforts
7
 * made by CHDK (http://chdk.wikia.com) and
8
 * Magic Lantern (http://www.magiclantern.fm) projects
9
 * contributors.
10
 *
11
 * See "Serial terminal" docs here:
12
 *   http://magiclantern.wikia.com/wiki/Register_Map#Misc_Registers
13
 *
14
 * The QEMU model of the Milkymist UART block by Michael Walle
15
 * is used as a template.
16
 *
17
 * This program is free software; you can redistribute it and/or modify
18
 * it under the terms of the GNU General Public License as published by
19
 * the Free Software Foundation; either version 2 of the License, or
20
 * (at your option) any later version.
21
 *
22
 * This program is distributed in the hope that it will be useful,
23
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25
 * GNU General Public License for more details.
26
 *
27
 */
28

    
29
#include "hw/hw.h"
30
#include "hw/sysbus.h"
31
#include "sysemu/char.h"
32

    
33
#include "hw/char/digic-uart.h"
34

    
35
enum {
36
    ST_RX_RDY = (1 << 0),
37
    ST_TX_RDY = (1 << 1),
38
};
39

    
40
static uint64_t digic_uart_read(void *opaque, hwaddr addr,
41
                                unsigned size)
42
{
43
    DigicUartState *s = opaque;
44
    uint64_t ret = 0;
45

    
46
    addr >>= 2;
47

    
48
    switch (addr) {
49
    case R_RX:
50
        s->reg_st &= ~(ST_RX_RDY);
51
        ret = s->reg_rx;
52
        break;
53

    
54
    case R_ST:
55
        ret = s->reg_st;
56
        break;
57

    
58
    default:
59
        qemu_log_mask(LOG_UNIMP,
60
                      "digic-uart: read access to unknown register 0x"
61
                      TARGET_FMT_plx, addr << 2);
62
    }
63

    
64
    return ret;
65
}
66

    
67
static void digic_uart_write(void *opaque, hwaddr addr, uint64_t value,
68
                             unsigned size)
69
{
70
    DigicUartState *s = opaque;
71
    unsigned char ch = value;
72

    
73
    addr >>= 2;
74

    
75
    switch (addr) {
76
    case R_TX:
77
        if (s->chr) {
78
            qemu_chr_fe_write_all(s->chr, &ch, 1);
79
        }
80
        break;
81

    
82
    case R_ST:
83
        /*
84
         * Ignore write to R_ST.
85
         *
86
         * The point is that this register is actively used
87
         * during receiving and transmitting symbols,
88
         * but we don't know the function of most of bits.
89
         *
90
         * Ignoring writes to R_ST is only a simplification
91
         * of the model. It has no perceptible side effects
92
         * for existing guests.
93
         */
94
        break;
95

    
96
    default:
97
        qemu_log_mask(LOG_UNIMP,
98
                      "digic-uart: write access to unknown register 0x"
99
                      TARGET_FMT_plx, addr << 2);
100
    }
101
}
102

    
103
static const MemoryRegionOps uart_mmio_ops = {
104
    .read = digic_uart_read,
105
    .write = digic_uart_write,
106
    .valid = {
107
        .min_access_size = 4,
108
        .max_access_size = 4,
109
    },
110
    .endianness = DEVICE_NATIVE_ENDIAN,
111
};
112

    
113
static int uart_can_rx(void *opaque)
114
{
115
    DigicUartState *s = opaque;
116

    
117
    return !(s->reg_st & ST_RX_RDY);
118
}
119

    
120
static void uart_rx(void *opaque, const uint8_t *buf, int size)
121
{
122
    DigicUartState *s = opaque;
123

    
124
    assert(uart_can_rx(opaque));
125

    
126
    s->reg_st |= ST_RX_RDY;
127
    s->reg_rx = *buf;
128
}
129

    
130
static void uart_event(void *opaque, int event)
131
{
132
}
133

    
134
static void digic_uart_reset(DeviceState *d)
135
{
136
    DigicUartState *s = DIGIC_UART(d);
137

    
138
    s->reg_rx = 0;
139
    s->reg_st = ST_TX_RDY;
140
}
141

    
142
static void digic_uart_realize(DeviceState *dev, Error **errp)
143
{
144
    DigicUartState *s = DIGIC_UART(dev);
145

    
146
    s->chr = qemu_char_get_next_serial();
147
    if (s->chr) {
148
        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
149
    }
150
}
151

    
152
static void digic_uart_init(Object *obj)
153
{
154
    DigicUartState *s = DIGIC_UART(obj);
155

    
156
    memory_region_init_io(&s->regs_region, OBJECT(s), &uart_mmio_ops, s,
157
                          TYPE_DIGIC_UART, 0x18);
158
    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->regs_region);
159
}
160

    
161
static const VMStateDescription vmstate_digic_uart = {
162
    .name = "digic-uart",
163
    .version_id = 1,
164
    .minimum_version_id = 1,
165
    .minimum_version_id_old = 1,
166
    .fields = (VMStateField[]) {
167
        VMSTATE_UINT32(reg_rx, DigicUartState),
168
        VMSTATE_UINT32(reg_st, DigicUartState),
169
        VMSTATE_END_OF_LIST()
170
    }
171
};
172

    
173
static void digic_uart_class_init(ObjectClass *klass, void *data)
174
{
175
    DeviceClass *dc = DEVICE_CLASS(klass);
176

    
177
    dc->realize = digic_uart_realize;
178
    dc->reset = digic_uart_reset;
179
    dc->vmsd = &vmstate_digic_uart;
180
}
181

    
182
static const TypeInfo digic_uart_info = {
183
    .name = TYPE_DIGIC_UART,
184
    .parent = TYPE_SYS_BUS_DEVICE,
185
    .instance_size = sizeof(DigicUartState),
186
    .instance_init = digic_uart_init,
187
    .class_init = digic_uart_class_init,
188
};
189

    
190
static void digic_uart_register_types(void)
191
{
192
    type_register_static(&digic_uart_info);
193
}
194

    
195
type_init(digic_uart_register_types)