Statistics
| Branch: | Revision:

root / hw / char / milkymist-uart.c @ 0434e30a

History | View | Annotate | Download (5.6 kB)

1 883de16b Michael Walle
/*
2 883de16b Michael Walle
 *  QEMU model of the Milkymist UART block.
3 883de16b Michael Walle
 *
4 883de16b Michael Walle
 *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
5 883de16b Michael Walle
 *
6 883de16b Michael Walle
 * This library is free software; you can redistribute it and/or
7 883de16b Michael Walle
 * modify it under the terms of the GNU Lesser General Public
8 883de16b Michael Walle
 * License as published by the Free Software Foundation; either
9 883de16b Michael Walle
 * version 2 of the License, or (at your option) any later version.
10 883de16b Michael Walle
 *
11 883de16b Michael Walle
 * This library is distributed in the hope that it will be useful,
12 883de16b Michael Walle
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 883de16b Michael Walle
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 883de16b Michael Walle
 * Lesser General Public License for more details.
15 883de16b Michael Walle
 *
16 883de16b Michael Walle
 * You should have received a copy of the GNU Lesser General Public
17 883de16b Michael Walle
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 883de16b Michael Walle
 *
19 883de16b Michael Walle
 *
20 883de16b Michael Walle
 * Specification available at:
21 883de16b Michael Walle
 *   http://www.milkymist.org/socdoc/uart.pdf
22 883de16b Michael Walle
 */
23 883de16b Michael Walle
24 83c9f4ca Paolo Bonzini
#include "hw/hw.h"
25 83c9f4ca Paolo Bonzini
#include "hw/sysbus.h"
26 883de16b Michael Walle
#include "trace.h"
27 927d4878 Paolo Bonzini
#include "char/char.h"
28 1de7afc9 Paolo Bonzini
#include "qemu/error-report.h"
29 883de16b Michael Walle
30 883de16b Michael Walle
enum {
31 883de16b Michael Walle
    R_RXTX = 0,
32 883de16b Michael Walle
    R_DIV,
33 fcfa3397 Michael Walle
    R_STAT,
34 fcfa3397 Michael Walle
    R_CTRL,
35 fcfa3397 Michael Walle
    R_DBG,
36 883de16b Michael Walle
    R_MAX
37 883de16b Michael Walle
};
38 883de16b Michael Walle
39 fcfa3397 Michael Walle
enum {
40 fcfa3397 Michael Walle
    STAT_THRE   = (1<<0),
41 fcfa3397 Michael Walle
    STAT_RX_EVT = (1<<1),
42 fcfa3397 Michael Walle
    STAT_TX_EVT = (1<<2),
43 fcfa3397 Michael Walle
};
44 fcfa3397 Michael Walle
45 fcfa3397 Michael Walle
enum {
46 fcfa3397 Michael Walle
    CTRL_RX_IRQ_EN = (1<<0),
47 fcfa3397 Michael Walle
    CTRL_TX_IRQ_EN = (1<<1),
48 fcfa3397 Michael Walle
    CTRL_THRU_EN   = (1<<2),
49 fcfa3397 Michael Walle
};
50 fcfa3397 Michael Walle
51 fcfa3397 Michael Walle
enum {
52 fcfa3397 Michael Walle
    DBG_BREAK_EN = (1<<0),
53 fcfa3397 Michael Walle
};
54 fcfa3397 Michael Walle
55 883de16b Michael Walle
struct MilkymistUartState {
56 883de16b Michael Walle
    SysBusDevice busdev;
57 5adb30d3 Michael Walle
    MemoryRegion regs_region;
58 883de16b Michael Walle
    CharDriverState *chr;
59 fcfa3397 Michael Walle
    qemu_irq irq;
60 883de16b Michael Walle
61 883de16b Michael Walle
    uint32_t regs[R_MAX];
62 883de16b Michael Walle
};
63 883de16b Michael Walle
typedef struct MilkymistUartState MilkymistUartState;
64 883de16b Michael Walle
65 fcfa3397 Michael Walle
static void uart_update_irq(MilkymistUartState *s)
66 fcfa3397 Michael Walle
{
67 fcfa3397 Michael Walle
    int rx_event = s->regs[R_STAT] & STAT_RX_EVT;
68 fcfa3397 Michael Walle
    int tx_event = s->regs[R_STAT] & STAT_TX_EVT;
69 fcfa3397 Michael Walle
    int rx_irq_en = s->regs[R_CTRL] & CTRL_RX_IRQ_EN;
70 fcfa3397 Michael Walle
    int tx_irq_en = s->regs[R_CTRL] & CTRL_TX_IRQ_EN;
71 fcfa3397 Michael Walle
72 fcfa3397 Michael Walle
    if ((rx_irq_en && rx_event) || (tx_irq_en && tx_event)) {
73 fcfa3397 Michael Walle
        trace_milkymist_uart_raise_irq();
74 fcfa3397 Michael Walle
        qemu_irq_raise(s->irq);
75 fcfa3397 Michael Walle
    } else {
76 fcfa3397 Michael Walle
        trace_milkymist_uart_lower_irq();
77 fcfa3397 Michael Walle
        qemu_irq_lower(s->irq);
78 fcfa3397 Michael Walle
    }
79 fcfa3397 Michael Walle
}
80 fcfa3397 Michael Walle
81 a8170e5e Avi Kivity
static uint64_t uart_read(void *opaque, hwaddr addr,
82 5adb30d3 Michael Walle
                          unsigned size)
83 883de16b Michael Walle
{
84 883de16b Michael Walle
    MilkymistUartState *s = opaque;
85 883de16b Michael Walle
    uint32_t r = 0;
86 883de16b Michael Walle
87 883de16b Michael Walle
    addr >>= 2;
88 883de16b Michael Walle
    switch (addr) {
89 883de16b Michael Walle
    case R_RXTX:
90 fcfa3397 Michael Walle
        r = s->regs[addr];
91 fcfa3397 Michael Walle
        break;
92 883de16b Michael Walle
    case R_DIV:
93 fcfa3397 Michael Walle
    case R_STAT:
94 fcfa3397 Michael Walle
    case R_CTRL:
95 fcfa3397 Michael Walle
    case R_DBG:
96 883de16b Michael Walle
        r = s->regs[addr];
97 883de16b Michael Walle
        break;
98 883de16b Michael Walle
99 883de16b Michael Walle
    default:
100 883de16b Michael Walle
        error_report("milkymist_uart: read access to unknown register 0x"
101 883de16b Michael Walle
                TARGET_FMT_plx, addr << 2);
102 883de16b Michael Walle
        break;
103 883de16b Michael Walle
    }
104 883de16b Michael Walle
105 883de16b Michael Walle
    trace_milkymist_uart_memory_read(addr << 2, r);
106 883de16b Michael Walle
107 883de16b Michael Walle
    return r;
108 883de16b Michael Walle
}
109 883de16b Michael Walle
110 a8170e5e Avi Kivity
static void uart_write(void *opaque, hwaddr addr, uint64_t value,
111 5adb30d3 Michael Walle
                       unsigned size)
112 883de16b Michael Walle
{
113 883de16b Michael Walle
    MilkymistUartState *s = opaque;
114 883de16b Michael Walle
    unsigned char ch = value;
115 883de16b Michael Walle
116 883de16b Michael Walle
    trace_milkymist_uart_memory_write(addr, value);
117 883de16b Michael Walle
118 883de16b Michael Walle
    addr >>= 2;
119 883de16b Michael Walle
    switch (addr) {
120 883de16b Michael Walle
    case R_RXTX:
121 883de16b Michael Walle
        if (s->chr) {
122 2cc6e0a1 Anthony Liguori
            qemu_chr_fe_write(s->chr, &ch, 1);
123 883de16b Michael Walle
        }
124 fcfa3397 Michael Walle
        s->regs[R_STAT] |= STAT_TX_EVT;
125 883de16b Michael Walle
        break;
126 883de16b Michael Walle
    case R_DIV:
127 fcfa3397 Michael Walle
    case R_CTRL:
128 fcfa3397 Michael Walle
    case R_DBG:
129 883de16b Michael Walle
        s->regs[addr] = value;
130 883de16b Michael Walle
        break;
131 883de16b Michael Walle
132 fcfa3397 Michael Walle
    case R_STAT:
133 fcfa3397 Michael Walle
        /* write one to clear bits */
134 fcfa3397 Michael Walle
        s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT));
135 44ac582d Michael Walle
        qemu_chr_accept_input(s->chr);
136 fcfa3397 Michael Walle
        break;
137 fcfa3397 Michael Walle
138 883de16b Michael Walle
    default:
139 883de16b Michael Walle
        error_report("milkymist_uart: write access to unknown register 0x"
140 883de16b Michael Walle
                TARGET_FMT_plx, addr << 2);
141 883de16b Michael Walle
        break;
142 883de16b Michael Walle
    }
143 fcfa3397 Michael Walle
144 fcfa3397 Michael Walle
    uart_update_irq(s);
145 883de16b Michael Walle
}
146 883de16b Michael Walle
147 5adb30d3 Michael Walle
static const MemoryRegionOps uart_mmio_ops = {
148 5adb30d3 Michael Walle
    .read = uart_read,
149 5adb30d3 Michael Walle
    .write = uart_write,
150 5adb30d3 Michael Walle
    .valid = {
151 5adb30d3 Michael Walle
        .min_access_size = 4,
152 5adb30d3 Michael Walle
        .max_access_size = 4,
153 5adb30d3 Michael Walle
    },
154 5adb30d3 Michael Walle
    .endianness = DEVICE_NATIVE_ENDIAN,
155 883de16b Michael Walle
};
156 883de16b Michael Walle
157 883de16b Michael Walle
static void uart_rx(void *opaque, const uint8_t *buf, int size)
158 883de16b Michael Walle
{
159 883de16b Michael Walle
    MilkymistUartState *s = opaque;
160 883de16b Michael Walle
161 fcfa3397 Michael Walle
    assert(!(s->regs[R_STAT] & STAT_RX_EVT));
162 fcfa3397 Michael Walle
163 fcfa3397 Michael Walle
    s->regs[R_STAT] |= STAT_RX_EVT;
164 883de16b Michael Walle
    s->regs[R_RXTX] = *buf;
165 fcfa3397 Michael Walle
166 fcfa3397 Michael Walle
    uart_update_irq(s);
167 883de16b Michael Walle
}
168 883de16b Michael Walle
169 883de16b Michael Walle
static int uart_can_rx(void *opaque)
170 883de16b Michael Walle
{
171 fcfa3397 Michael Walle
    MilkymistUartState *s = opaque;
172 fcfa3397 Michael Walle
173 fcfa3397 Michael Walle
    return !(s->regs[R_STAT] & STAT_RX_EVT);
174 883de16b Michael Walle
}
175 883de16b Michael Walle
176 883de16b Michael Walle
static void uart_event(void *opaque, int event)
177 883de16b Michael Walle
{
178 883de16b Michael Walle
}
179 883de16b Michael Walle
180 883de16b Michael Walle
static void milkymist_uart_reset(DeviceState *d)
181 883de16b Michael Walle
{
182 883de16b Michael Walle
    MilkymistUartState *s = container_of(d, MilkymistUartState, busdev.qdev);
183 883de16b Michael Walle
    int i;
184 883de16b Michael Walle
185 883de16b Michael Walle
    for (i = 0; i < R_MAX; i++) {
186 883de16b Michael Walle
        s->regs[i] = 0;
187 883de16b Michael Walle
    }
188 fcfa3397 Michael Walle
189 fcfa3397 Michael Walle
    /* THRE is always set */
190 fcfa3397 Michael Walle
    s->regs[R_STAT] = STAT_THRE;
191 883de16b Michael Walle
}
192 883de16b Michael Walle
193 883de16b Michael Walle
static int milkymist_uart_init(SysBusDevice *dev)
194 883de16b Michael Walle
{
195 883de16b Michael Walle
    MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev);
196 883de16b Michael Walle
197 fcfa3397 Michael Walle
    sysbus_init_irq(dev, &s->irq);
198 883de16b Michael Walle
199 5adb30d3 Michael Walle
    memory_region_init_io(&s->regs_region, &uart_mmio_ops, s,
200 5adb30d3 Michael Walle
            "milkymist-uart", R_MAX * 4);
201 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->regs_region);
202 883de16b Michael Walle
203 0beb4942 Anthony Liguori
    s->chr = qemu_char_get_next_serial();
204 883de16b Michael Walle
    if (s->chr) {
205 883de16b Michael Walle
        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
206 883de16b Michael Walle
    }
207 883de16b Michael Walle
208 883de16b Michael Walle
    return 0;
209 883de16b Michael Walle
}
210 883de16b Michael Walle
211 883de16b Michael Walle
static const VMStateDescription vmstate_milkymist_uart = {
212 883de16b Michael Walle
    .name = "milkymist-uart",
213 883de16b Michael Walle
    .version_id = 1,
214 883de16b Michael Walle
    .minimum_version_id = 1,
215 883de16b Michael Walle
    .minimum_version_id_old = 1,
216 883de16b Michael Walle
    .fields      = (VMStateField[]) {
217 883de16b Michael Walle
        VMSTATE_UINT32_ARRAY(regs, MilkymistUartState, R_MAX),
218 883de16b Michael Walle
        VMSTATE_END_OF_LIST()
219 883de16b Michael Walle
    }
220 883de16b Michael Walle
};
221 883de16b Michael Walle
222 999e12bb Anthony Liguori
static void milkymist_uart_class_init(ObjectClass *klass, void *data)
223 999e12bb Anthony Liguori
{
224 39bffca2 Anthony Liguori
    DeviceClass *dc = DEVICE_CLASS(klass);
225 999e12bb Anthony Liguori
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
226 999e12bb Anthony Liguori
227 999e12bb Anthony Liguori
    k->init = milkymist_uart_init;
228 39bffca2 Anthony Liguori
    dc->reset = milkymist_uart_reset;
229 39bffca2 Anthony Liguori
    dc->vmsd = &vmstate_milkymist_uart;
230 999e12bb Anthony Liguori
}
231 999e12bb Anthony Liguori
232 8c43a6f0 Andreas Färber
static const TypeInfo milkymist_uart_info = {
233 39bffca2 Anthony Liguori
    .name          = "milkymist-uart",
234 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
235 39bffca2 Anthony Liguori
    .instance_size = sizeof(MilkymistUartState),
236 39bffca2 Anthony Liguori
    .class_init    = milkymist_uart_class_init,
237 883de16b Michael Walle
};
238 883de16b Michael Walle
239 83f7d43a Andreas Färber
static void milkymist_uart_register_types(void)
240 883de16b Michael Walle
{
241 39bffca2 Anthony Liguori
    type_register_static(&milkymist_uart_info);
242 883de16b Michael Walle
}
243 883de16b Michael Walle
244 83f7d43a Andreas Färber
type_init(milkymist_uart_register_types)