root / hw / milkymist-uart.c @ 81b1008d
History | View | Annotate | Download (4.2 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 | 883de16b | Michael Walle | R_MAX |
34 | 883de16b | Michael Walle | }; |
35 | 883de16b | Michael Walle | |
36 | 883de16b | Michael Walle | struct MilkymistUartState {
|
37 | 883de16b | Michael Walle | SysBusDevice busdev; |
38 | 883de16b | Michael Walle | CharDriverState *chr; |
39 | 883de16b | Michael Walle | qemu_irq rx_irq; |
40 | 883de16b | Michael Walle | qemu_irq tx_irq; |
41 | 883de16b | Michael Walle | |
42 | 883de16b | Michael Walle | uint32_t regs[R_MAX]; |
43 | 883de16b | Michael Walle | }; |
44 | 883de16b | Michael Walle | typedef struct MilkymistUartState MilkymistUartState; |
45 | 883de16b | Michael Walle | |
46 | 883de16b | Michael Walle | static uint32_t uart_read(void *opaque, target_phys_addr_t addr) |
47 | 883de16b | Michael Walle | { |
48 | 883de16b | Michael Walle | MilkymistUartState *s = opaque; |
49 | 883de16b | Michael Walle | uint32_t r = 0;
|
50 | 883de16b | Michael Walle | |
51 | 883de16b | Michael Walle | addr >>= 2;
|
52 | 883de16b | Michael Walle | switch (addr) {
|
53 | 883de16b | Michael Walle | case R_RXTX:
|
54 | 883de16b | Michael Walle | case R_DIV:
|
55 | 883de16b | Michael Walle | r = s->regs[addr]; |
56 | 883de16b | Michael Walle | break;
|
57 | 883de16b | Michael Walle | |
58 | 883de16b | Michael Walle | default:
|
59 | 883de16b | Michael Walle | error_report("milkymist_uart: read access to unknown register 0x"
|
60 | 883de16b | Michael Walle | TARGET_FMT_plx, addr << 2);
|
61 | 883de16b | Michael Walle | break;
|
62 | 883de16b | Michael Walle | } |
63 | 883de16b | Michael Walle | |
64 | 883de16b | Michael Walle | trace_milkymist_uart_memory_read(addr << 2, r);
|
65 | 883de16b | Michael Walle | |
66 | 883de16b | Michael Walle | return r;
|
67 | 883de16b | Michael Walle | } |
68 | 883de16b | Michael Walle | |
69 | 883de16b | Michael Walle | static void uart_write(void *opaque, target_phys_addr_t addr, uint32_t value) |
70 | 883de16b | Michael Walle | { |
71 | 883de16b | Michael Walle | MilkymistUartState *s = opaque; |
72 | 883de16b | Michael Walle | unsigned char ch = value; |
73 | 883de16b | Michael Walle | |
74 | 883de16b | Michael Walle | trace_milkymist_uart_memory_write(addr, value); |
75 | 883de16b | Michael Walle | |
76 | 883de16b | Michael Walle | addr >>= 2;
|
77 | 883de16b | Michael Walle | switch (addr) {
|
78 | 883de16b | Michael Walle | case R_RXTX:
|
79 | 883de16b | Michael Walle | if (s->chr) {
|
80 | 2cc6e0a1 | Anthony Liguori | qemu_chr_fe_write(s->chr, &ch, 1);
|
81 | 883de16b | Michael Walle | } |
82 | 883de16b | Michael Walle | trace_milkymist_uart_pulse_irq_tx(); |
83 | 883de16b | Michael Walle | qemu_irq_pulse(s->tx_irq); |
84 | 883de16b | Michael Walle | break;
|
85 | 883de16b | Michael Walle | case R_DIV:
|
86 | 883de16b | Michael Walle | s->regs[addr] = value; |
87 | 883de16b | Michael Walle | break;
|
88 | 883de16b | Michael Walle | |
89 | 883de16b | Michael Walle | default:
|
90 | 883de16b | Michael Walle | error_report("milkymist_uart: write access to unknown register 0x"
|
91 | 883de16b | Michael Walle | TARGET_FMT_plx, addr << 2);
|
92 | 883de16b | Michael Walle | break;
|
93 | 883de16b | Michael Walle | } |
94 | 883de16b | Michael Walle | } |
95 | 883de16b | Michael Walle | |
96 | 883de16b | Michael Walle | static CPUReadMemoryFunc * const uart_read_fn[] = { |
97 | 883de16b | Michael Walle | NULL,
|
98 | 883de16b | Michael Walle | NULL,
|
99 | 883de16b | Michael Walle | &uart_read, |
100 | 883de16b | Michael Walle | }; |
101 | 883de16b | Michael Walle | |
102 | 883de16b | Michael Walle | static CPUWriteMemoryFunc * const uart_write_fn[] = { |
103 | 883de16b | Michael Walle | NULL,
|
104 | 883de16b | Michael Walle | NULL,
|
105 | 883de16b | Michael Walle | &uart_write, |
106 | 883de16b | Michael Walle | }; |
107 | 883de16b | Michael Walle | |
108 | 883de16b | Michael Walle | static void uart_rx(void *opaque, const uint8_t *buf, int size) |
109 | 883de16b | Michael Walle | { |
110 | 883de16b | Michael Walle | MilkymistUartState *s = opaque; |
111 | 883de16b | Michael Walle | |
112 | 883de16b | Michael Walle | s->regs[R_RXTX] = *buf; |
113 | 883de16b | Michael Walle | trace_milkymist_uart_pulse_irq_rx(); |
114 | 883de16b | Michael Walle | qemu_irq_pulse(s->rx_irq); |
115 | 883de16b | Michael Walle | } |
116 | 883de16b | Michael Walle | |
117 | 883de16b | Michael Walle | static int uart_can_rx(void *opaque) |
118 | 883de16b | Michael Walle | { |
119 | 883de16b | Michael Walle | return 1; |
120 | 883de16b | Michael Walle | } |
121 | 883de16b | Michael Walle | |
122 | 883de16b | Michael Walle | static void uart_event(void *opaque, int event) |
123 | 883de16b | Michael Walle | { |
124 | 883de16b | Michael Walle | } |
125 | 883de16b | Michael Walle | |
126 | 883de16b | Michael Walle | static void milkymist_uart_reset(DeviceState *d) |
127 | 883de16b | Michael Walle | { |
128 | 883de16b | Michael Walle | MilkymistUartState *s = container_of(d, MilkymistUartState, busdev.qdev); |
129 | 883de16b | Michael Walle | int i;
|
130 | 883de16b | Michael Walle | |
131 | 883de16b | Michael Walle | for (i = 0; i < R_MAX; i++) { |
132 | 883de16b | Michael Walle | s->regs[i] = 0;
|
133 | 883de16b | Michael Walle | } |
134 | 883de16b | Michael Walle | } |
135 | 883de16b | Michael Walle | |
136 | 883de16b | Michael Walle | static int milkymist_uart_init(SysBusDevice *dev) |
137 | 883de16b | Michael Walle | { |
138 | 883de16b | Michael Walle | MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev); |
139 | 883de16b | Michael Walle | int uart_regs;
|
140 | 883de16b | Michael Walle | |
141 | 883de16b | Michael Walle | sysbus_init_irq(dev, &s->rx_irq); |
142 | 883de16b | Michael Walle | sysbus_init_irq(dev, &s->tx_irq); |
143 | 883de16b | Michael Walle | |
144 | 883de16b | Michael Walle | uart_regs = cpu_register_io_memory(uart_read_fn, uart_write_fn, s, |
145 | 883de16b | Michael Walle | DEVICE_NATIVE_ENDIAN); |
146 | 883de16b | Michael Walle | sysbus_init_mmio(dev, R_MAX * 4, uart_regs);
|
147 | 883de16b | Michael Walle | |
148 | 883de16b | Michael Walle | s->chr = qdev_init_chardev(&dev->qdev); |
149 | 883de16b | Michael Walle | if (s->chr) {
|
150 | 883de16b | Michael Walle | qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); |
151 | 883de16b | Michael Walle | } |
152 | 883de16b | Michael Walle | |
153 | 883de16b | Michael Walle | return 0; |
154 | 883de16b | Michael Walle | } |
155 | 883de16b | Michael Walle | |
156 | 883de16b | Michael Walle | static const VMStateDescription vmstate_milkymist_uart = { |
157 | 883de16b | Michael Walle | .name = "milkymist-uart",
|
158 | 883de16b | Michael Walle | .version_id = 1,
|
159 | 883de16b | Michael Walle | .minimum_version_id = 1,
|
160 | 883de16b | Michael Walle | .minimum_version_id_old = 1,
|
161 | 883de16b | Michael Walle | .fields = (VMStateField[]) { |
162 | 883de16b | Michael Walle | VMSTATE_UINT32_ARRAY(regs, MilkymistUartState, R_MAX), |
163 | 883de16b | Michael Walle | VMSTATE_END_OF_LIST() |
164 | 883de16b | Michael Walle | } |
165 | 883de16b | Michael Walle | }; |
166 | 883de16b | Michael Walle | |
167 | 883de16b | Michael Walle | static SysBusDeviceInfo milkymist_uart_info = {
|
168 | 883de16b | Michael Walle | .init = milkymist_uart_init, |
169 | 883de16b | Michael Walle | .qdev.name = "milkymist-uart",
|
170 | 883de16b | Michael Walle | .qdev.size = sizeof(MilkymistUartState),
|
171 | 883de16b | Michael Walle | .qdev.vmsd = &vmstate_milkymist_uart, |
172 | 883de16b | Michael Walle | .qdev.reset = milkymist_uart_reset, |
173 | 883de16b | Michael Walle | }; |
174 | 883de16b | Michael Walle | |
175 | 883de16b | Michael Walle | static void milkymist_uart_register(void) |
176 | 883de16b | Michael Walle | { |
177 | 883de16b | Michael Walle | sysbus_register_withprop(&milkymist_uart_info); |
178 | 883de16b | Michael Walle | } |
179 | 883de16b | Michael Walle | |
180 | 883de16b | Michael Walle | device_init(milkymist_uart_register) |