Statistics
| Branch: | Revision:

root / hw / milkymist-uart.c @ 0200db65

History | View | Annotate | Download (5.4 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 883de16b Michael Walle
#include "hw.h"
25 883de16b Michael Walle
#include "sysbus.h"
26 883de16b Michael Walle
#include "trace.h"
27 883de16b Michael Walle
#include "qemu-char.h"
28 883de16b Michael Walle
#include "qemu-error.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 5adb30d3 Michael Walle
static uint64_t uart_read(void *opaque, target_phys_addr_t 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 5adb30d3 Michael Walle
static void uart_write(void *opaque, target_phys_addr_t 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 fcfa3397 Michael Walle
        break;
136 fcfa3397 Michael Walle
137 883de16b Michael Walle
    default:
138 883de16b Michael Walle
        error_report("milkymist_uart: write access to unknown register 0x"
139 883de16b Michael Walle
                TARGET_FMT_plx, addr << 2);
140 883de16b Michael Walle
        break;
141 883de16b Michael Walle
    }
142 fcfa3397 Michael Walle
143 fcfa3397 Michael Walle
    uart_update_irq(s);
144 883de16b Michael Walle
}
145 883de16b Michael Walle
146 5adb30d3 Michael Walle
static const MemoryRegionOps uart_mmio_ops = {
147 5adb30d3 Michael Walle
    .read = uart_read,
148 5adb30d3 Michael Walle
    .write = uart_write,
149 5adb30d3 Michael Walle
    .valid = {
150 5adb30d3 Michael Walle
        .min_access_size = 4,
151 5adb30d3 Michael Walle
        .max_access_size = 4,
152 5adb30d3 Michael Walle
    },
153 5adb30d3 Michael Walle
    .endianness = DEVICE_NATIVE_ENDIAN,
154 883de16b Michael Walle
};
155 883de16b Michael Walle
156 883de16b Michael Walle
static void uart_rx(void *opaque, const uint8_t *buf, int size)
157 883de16b Michael Walle
{
158 883de16b Michael Walle
    MilkymistUartState *s = opaque;
159 883de16b Michael Walle
160 fcfa3397 Michael Walle
    assert(!(s->regs[R_STAT] & STAT_RX_EVT));
161 fcfa3397 Michael Walle
162 fcfa3397 Michael Walle
    s->regs[R_STAT] |= STAT_RX_EVT;
163 883de16b Michael Walle
    s->regs[R_RXTX] = *buf;
164 fcfa3397 Michael Walle
165 fcfa3397 Michael Walle
    uart_update_irq(s);
166 883de16b Michael Walle
}
167 883de16b Michael Walle
168 883de16b Michael Walle
static int uart_can_rx(void *opaque)
169 883de16b Michael Walle
{
170 fcfa3397 Michael Walle
    MilkymistUartState *s = opaque;
171 fcfa3397 Michael Walle
172 fcfa3397 Michael Walle
    return !(s->regs[R_STAT] & STAT_RX_EVT);
173 883de16b Michael Walle
}
174 883de16b Michael Walle
175 883de16b Michael Walle
static void uart_event(void *opaque, int event)
176 883de16b Michael Walle
{
177 883de16b Michael Walle
}
178 883de16b Michael Walle
179 883de16b Michael Walle
static void milkymist_uart_reset(DeviceState *d)
180 883de16b Michael Walle
{
181 883de16b Michael Walle
    MilkymistUartState *s = container_of(d, MilkymistUartState, busdev.qdev);
182 883de16b Michael Walle
    int i;
183 883de16b Michael Walle
184 883de16b Michael Walle
    for (i = 0; i < R_MAX; i++) {
185 883de16b Michael Walle
        s->regs[i] = 0;
186 883de16b Michael Walle
    }
187 fcfa3397 Michael Walle
188 fcfa3397 Michael Walle
    /* THRE is always set */
189 fcfa3397 Michael Walle
    s->regs[R_STAT] = STAT_THRE;
190 883de16b Michael Walle
}
191 883de16b Michael Walle
192 883de16b Michael Walle
static int milkymist_uart_init(SysBusDevice *dev)
193 883de16b Michael Walle
{
194 883de16b Michael Walle
    MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev);
195 883de16b Michael Walle
196 fcfa3397 Michael Walle
    sysbus_init_irq(dev, &s->irq);
197 883de16b Michael Walle
198 5adb30d3 Michael Walle
    memory_region_init_io(&s->regs_region, &uart_mmio_ops, s,
199 5adb30d3 Michael Walle
            "milkymist-uart", R_MAX * 4);
200 5adb30d3 Michael Walle
    sysbus_init_mmio_region(dev, &s->regs_region);
201 883de16b Michael Walle
202 883de16b Michael Walle
    s->chr = qdev_init_chardev(&dev->qdev);
203 883de16b Michael Walle
    if (s->chr) {
204 883de16b Michael Walle
        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
205 883de16b Michael Walle
    }
206 883de16b Michael Walle
207 883de16b Michael Walle
    return 0;
208 883de16b Michael Walle
}
209 883de16b Michael Walle
210 883de16b Michael Walle
static const VMStateDescription vmstate_milkymist_uart = {
211 883de16b Michael Walle
    .name = "milkymist-uart",
212 883de16b Michael Walle
    .version_id = 1,
213 883de16b Michael Walle
    .minimum_version_id = 1,
214 883de16b Michael Walle
    .minimum_version_id_old = 1,
215 883de16b Michael Walle
    .fields      = (VMStateField[]) {
216 883de16b Michael Walle
        VMSTATE_UINT32_ARRAY(regs, MilkymistUartState, R_MAX),
217 883de16b Michael Walle
        VMSTATE_END_OF_LIST()
218 883de16b Michael Walle
    }
219 883de16b Michael Walle
};
220 883de16b Michael Walle
221 883de16b Michael Walle
static SysBusDeviceInfo milkymist_uart_info = {
222 883de16b Michael Walle
    .init = milkymist_uart_init,
223 883de16b Michael Walle
    .qdev.name  = "milkymist-uart",
224 883de16b Michael Walle
    .qdev.size  = sizeof(MilkymistUartState),
225 883de16b Michael Walle
    .qdev.vmsd  = &vmstate_milkymist_uart,
226 883de16b Michael Walle
    .qdev.reset = milkymist_uart_reset,
227 883de16b Michael Walle
};
228 883de16b Michael Walle
229 883de16b Michael Walle
static void milkymist_uart_register(void)
230 883de16b Michael Walle
{
231 883de16b Michael Walle
    sysbus_register_withprop(&milkymist_uart_info);
232 883de16b Michael Walle
}
233 883de16b Michael Walle
234 883de16b Michael Walle
device_init(milkymist_uart_register)