root / hw / xilinx_uartlite.c @ 7bc3018b
History | View | Annotate | Download (5.9 kB)
1 | ee118d95 | Edgar E. Iglesias | /*
|
---|---|---|---|
2 | ee118d95 | Edgar E. Iglesias | * QEMU model of Xilinx uartlite.
|
3 | ee118d95 | Edgar E. Iglesias | *
|
4 | ee118d95 | Edgar E. Iglesias | * Copyright (c) 2009 Edgar E. Iglesias.
|
5 | ee118d95 | Edgar E. Iglesias | *
|
6 | ee118d95 | Edgar E. Iglesias | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | ee118d95 | Edgar E. Iglesias | * of this software and associated documentation files (the "Software"), to deal
|
8 | ee118d95 | Edgar E. Iglesias | * in the Software without restriction, including without limitation the rights
|
9 | ee118d95 | Edgar E. Iglesias | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | ee118d95 | Edgar E. Iglesias | * copies of the Software, and to permit persons to whom the Software is
|
11 | ee118d95 | Edgar E. Iglesias | * furnished to do so, subject to the following conditions:
|
12 | ee118d95 | Edgar E. Iglesias | *
|
13 | ee118d95 | Edgar E. Iglesias | * The above copyright notice and this permission notice shall be included in
|
14 | ee118d95 | Edgar E. Iglesias | * all copies or substantial portions of the Software.
|
15 | ee118d95 | Edgar E. Iglesias | *
|
16 | ee118d95 | Edgar E. Iglesias | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | ee118d95 | Edgar E. Iglesias | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | ee118d95 | Edgar E. Iglesias | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | ee118d95 | Edgar E. Iglesias | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | ee118d95 | Edgar E. Iglesias | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | ee118d95 | Edgar E. Iglesias | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | ee118d95 | Edgar E. Iglesias | * THE SOFTWARE.
|
23 | ee118d95 | Edgar E. Iglesias | */
|
24 | ee118d95 | Edgar E. Iglesias | |
25 | ee118d95 | Edgar E. Iglesias | #include "sysbus.h" |
26 | ee118d95 | Edgar E. Iglesias | #include "qemu-char.h" |
27 | ee118d95 | Edgar E. Iglesias | |
28 | ee118d95 | Edgar E. Iglesias | #define DUART(x)
|
29 | ee118d95 | Edgar E. Iglesias | |
30 | ee118d95 | Edgar E. Iglesias | #define R_RX 0 |
31 | ee118d95 | Edgar E. Iglesias | #define R_TX 1 |
32 | ee118d95 | Edgar E. Iglesias | #define R_STATUS 2 |
33 | ee118d95 | Edgar E. Iglesias | #define R_CTRL 3 |
34 | ee118d95 | Edgar E. Iglesias | #define R_MAX 4 |
35 | ee118d95 | Edgar E. Iglesias | |
36 | ee118d95 | Edgar E. Iglesias | #define STATUS_RXVALID 0x01 |
37 | ee118d95 | Edgar E. Iglesias | #define STATUS_RXFULL 0x02 |
38 | ee118d95 | Edgar E. Iglesias | #define STATUS_TXEMPTY 0x04 |
39 | ee118d95 | Edgar E. Iglesias | #define STATUS_TXFULL 0x08 |
40 | ee118d95 | Edgar E. Iglesias | #define STATUS_IE 0x10 |
41 | ee118d95 | Edgar E. Iglesias | #define STATUS_OVERRUN 0x20 |
42 | ee118d95 | Edgar E. Iglesias | #define STATUS_FRAME 0x40 |
43 | ee118d95 | Edgar E. Iglesias | #define STATUS_PARITY 0x80 |
44 | ee118d95 | Edgar E. Iglesias | |
45 | ee118d95 | Edgar E. Iglesias | #define CONTROL_RST_TX 0x01 |
46 | ee118d95 | Edgar E. Iglesias | #define CONTROL_RST_RX 0x02 |
47 | ee118d95 | Edgar E. Iglesias | #define CONTROL_IE 0x10 |
48 | ee118d95 | Edgar E. Iglesias | |
49 | ee118d95 | Edgar E. Iglesias | struct xlx_uartlite
|
50 | ee118d95 | Edgar E. Iglesias | { |
51 | ee118d95 | Edgar E. Iglesias | SysBusDevice busdev; |
52 | 010f3f5f | Edgar E. Iglesias | MemoryRegion mmio; |
53 | ee118d95 | Edgar E. Iglesias | CharDriverState *chr; |
54 | ee118d95 | Edgar E. Iglesias | qemu_irq irq; |
55 | ee118d95 | Edgar E. Iglesias | |
56 | ee118d95 | Edgar E. Iglesias | uint8_t rx_fifo[8];
|
57 | ee118d95 | Edgar E. Iglesias | unsigned int rx_fifo_pos; |
58 | ee118d95 | Edgar E. Iglesias | unsigned int rx_fifo_len; |
59 | ee118d95 | Edgar E. Iglesias | |
60 | ee118d95 | Edgar E. Iglesias | uint32_t regs[R_MAX]; |
61 | ee118d95 | Edgar E. Iglesias | }; |
62 | ee118d95 | Edgar E. Iglesias | |
63 | ee118d95 | Edgar E. Iglesias | static void uart_update_irq(struct xlx_uartlite *s) |
64 | ee118d95 | Edgar E. Iglesias | { |
65 | ee118d95 | Edgar E. Iglesias | unsigned int irq; |
66 | ee118d95 | Edgar E. Iglesias | |
67 | ee118d95 | Edgar E. Iglesias | if (s->rx_fifo_len)
|
68 | ee118d95 | Edgar E. Iglesias | s->regs[R_STATUS] |= STATUS_IE; |
69 | ee118d95 | Edgar E. Iglesias | |
70 | ee118d95 | Edgar E. Iglesias | irq = (s->regs[R_STATUS] & STATUS_IE) && (s->regs[R_CTRL] & CONTROL_IE); |
71 | ee118d95 | Edgar E. Iglesias | qemu_set_irq(s->irq, irq); |
72 | ee118d95 | Edgar E. Iglesias | } |
73 | ee118d95 | Edgar E. Iglesias | |
74 | ee118d95 | Edgar E. Iglesias | static void uart_update_status(struct xlx_uartlite *s) |
75 | ee118d95 | Edgar E. Iglesias | { |
76 | ee118d95 | Edgar E. Iglesias | uint32_t r; |
77 | ee118d95 | Edgar E. Iglesias | |
78 | ee118d95 | Edgar E. Iglesias | r = s->regs[R_STATUS]; |
79 | ee118d95 | Edgar E. Iglesias | r &= ~7;
|
80 | ee118d95 | Edgar E. Iglesias | r |= 1 << 2; /* Tx fifo is always empty. We are fast :) */ |
81 | ee118d95 | Edgar E. Iglesias | r |= (s->rx_fifo_len == sizeof (s->rx_fifo)) << 1; |
82 | ee118d95 | Edgar E. Iglesias | r |= (!!s->rx_fifo_len); |
83 | ee118d95 | Edgar E. Iglesias | s->regs[R_STATUS] = r; |
84 | ee118d95 | Edgar E. Iglesias | } |
85 | ee118d95 | Edgar E. Iglesias | |
86 | 010f3f5f | Edgar E. Iglesias | static uint64_t
|
87 | 010f3f5f | Edgar E. Iglesias | uart_read(void *opaque, target_phys_addr_t addr, unsigned int size) |
88 | ee118d95 | Edgar E. Iglesias | { |
89 | ee118d95 | Edgar E. Iglesias | struct xlx_uartlite *s = opaque;
|
90 | ee118d95 | Edgar E. Iglesias | uint32_t r = 0;
|
91 | ee118d95 | Edgar E. Iglesias | addr >>= 2;
|
92 | ee118d95 | Edgar E. Iglesias | switch (addr)
|
93 | ee118d95 | Edgar E. Iglesias | { |
94 | ee118d95 | Edgar E. Iglesias | case R_RX:
|
95 | ee118d95 | Edgar E. Iglesias | r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 7];
|
96 | ee118d95 | Edgar E. Iglesias | if (s->rx_fifo_len)
|
97 | ee118d95 | Edgar E. Iglesias | s->rx_fifo_len--; |
98 | ee118d95 | Edgar E. Iglesias | uart_update_status(s); |
99 | ee118d95 | Edgar E. Iglesias | uart_update_irq(s); |
100 | ee118d95 | Edgar E. Iglesias | break;
|
101 | ee118d95 | Edgar E. Iglesias | |
102 | ee118d95 | Edgar E. Iglesias | default:
|
103 | ee118d95 | Edgar E. Iglesias | if (addr < ARRAY_SIZE(s->regs))
|
104 | ee118d95 | Edgar E. Iglesias | r = s->regs[addr]; |
105 | ee118d95 | Edgar E. Iglesias | DUART(qemu_log("%s addr=%x v=%x\n", __func__, addr, r));
|
106 | ee118d95 | Edgar E. Iglesias | break;
|
107 | ee118d95 | Edgar E. Iglesias | } |
108 | ee118d95 | Edgar E. Iglesias | return r;
|
109 | ee118d95 | Edgar E. Iglesias | } |
110 | ee118d95 | Edgar E. Iglesias | |
111 | ee118d95 | Edgar E. Iglesias | static void |
112 | 010f3f5f | Edgar E. Iglesias | uart_write(void *opaque, target_phys_addr_t addr,
|
113 | 010f3f5f | Edgar E. Iglesias | uint64_t val64, unsigned int size) |
114 | ee118d95 | Edgar E. Iglesias | { |
115 | ee118d95 | Edgar E. Iglesias | struct xlx_uartlite *s = opaque;
|
116 | 010f3f5f | Edgar E. Iglesias | uint32_t value = val64; |
117 | ee118d95 | Edgar E. Iglesias | unsigned char ch = value; |
118 | ee118d95 | Edgar E. Iglesias | |
119 | ee118d95 | Edgar E. Iglesias | addr >>= 2;
|
120 | ee118d95 | Edgar E. Iglesias | switch (addr)
|
121 | ee118d95 | Edgar E. Iglesias | { |
122 | ee118d95 | Edgar E. Iglesias | case R_STATUS:
|
123 | ee118d95 | Edgar E. Iglesias | hw_error("write to UART STATUS?\n");
|
124 | ee118d95 | Edgar E. Iglesias | break;
|
125 | ee118d95 | Edgar E. Iglesias | |
126 | ee118d95 | Edgar E. Iglesias | case R_CTRL:
|
127 | ee118d95 | Edgar E. Iglesias | if (value & CONTROL_RST_RX) {
|
128 | ee118d95 | Edgar E. Iglesias | s->rx_fifo_pos = 0;
|
129 | ee118d95 | Edgar E. Iglesias | s->rx_fifo_len = 0;
|
130 | ee118d95 | Edgar E. Iglesias | } |
131 | ee118d95 | Edgar E. Iglesias | s->regs[addr] = value; |
132 | ee118d95 | Edgar E. Iglesias | break;
|
133 | ee118d95 | Edgar E. Iglesias | |
134 | ee118d95 | Edgar E. Iglesias | case R_TX:
|
135 | ee118d95 | Edgar E. Iglesias | if (s->chr)
|
136 | 2cc6e0a1 | Anthony Liguori | qemu_chr_fe_write(s->chr, &ch, 1);
|
137 | ee118d95 | Edgar E. Iglesias | |
138 | ee118d95 | Edgar E. Iglesias | s->regs[addr] = value; |
139 | ee118d95 | Edgar E. Iglesias | |
140 | ee118d95 | Edgar E. Iglesias | /* hax. */
|
141 | ee118d95 | Edgar E. Iglesias | s->regs[R_STATUS] |= STATUS_IE; |
142 | ee118d95 | Edgar E. Iglesias | break;
|
143 | ee118d95 | Edgar E. Iglesias | |
144 | ee118d95 | Edgar E. Iglesias | default:
|
145 | ee118d95 | Edgar E. Iglesias | DUART(printf("%s addr=%x v=%x\n", __func__, addr, value));
|
146 | ee118d95 | Edgar E. Iglesias | if (addr < ARRAY_SIZE(s->regs))
|
147 | ee118d95 | Edgar E. Iglesias | s->regs[addr] = value; |
148 | ee118d95 | Edgar E. Iglesias | break;
|
149 | ee118d95 | Edgar E. Iglesias | } |
150 | ee118d95 | Edgar E. Iglesias | uart_update_status(s); |
151 | ee118d95 | Edgar E. Iglesias | uart_update_irq(s); |
152 | ee118d95 | Edgar E. Iglesias | } |
153 | ee118d95 | Edgar E. Iglesias | |
154 | 010f3f5f | Edgar E. Iglesias | static const MemoryRegionOps uart_ops = { |
155 | 010f3f5f | Edgar E. Iglesias | .read = uart_read, |
156 | 010f3f5f | Edgar E. Iglesias | .write = uart_write, |
157 | 010f3f5f | Edgar E. Iglesias | .endianness = DEVICE_NATIVE_ENDIAN, |
158 | 010f3f5f | Edgar E. Iglesias | .valid = { |
159 | 010f3f5f | Edgar E. Iglesias | .min_access_size = 1,
|
160 | 010f3f5f | Edgar E. Iglesias | .max_access_size = 4
|
161 | 010f3f5f | Edgar E. Iglesias | } |
162 | ee118d95 | Edgar E. Iglesias | }; |
163 | ee118d95 | Edgar E. Iglesias | |
164 | ee118d95 | Edgar E. Iglesias | static void uart_rx(void *opaque, const uint8_t *buf, int size) |
165 | ee118d95 | Edgar E. Iglesias | { |
166 | ee118d95 | Edgar E. Iglesias | struct xlx_uartlite *s = opaque;
|
167 | ee118d95 | Edgar E. Iglesias | |
168 | ee118d95 | Edgar E. Iglesias | /* Got a byte. */
|
169 | ee118d95 | Edgar E. Iglesias | if (s->rx_fifo_len >= 8) { |
170 | ee118d95 | Edgar E. Iglesias | printf("WARNING: UART dropped char.\n");
|
171 | ee118d95 | Edgar E. Iglesias | return;
|
172 | ee118d95 | Edgar E. Iglesias | } |
173 | ee118d95 | Edgar E. Iglesias | s->rx_fifo[s->rx_fifo_pos] = *buf; |
174 | ee118d95 | Edgar E. Iglesias | s->rx_fifo_pos++; |
175 | ee118d95 | Edgar E. Iglesias | s->rx_fifo_pos &= 0x7;
|
176 | ee118d95 | Edgar E. Iglesias | s->rx_fifo_len++; |
177 | ee118d95 | Edgar E. Iglesias | |
178 | ee118d95 | Edgar E. Iglesias | uart_update_status(s); |
179 | ee118d95 | Edgar E. Iglesias | uart_update_irq(s); |
180 | ee118d95 | Edgar E. Iglesias | } |
181 | ee118d95 | Edgar E. Iglesias | |
182 | ee118d95 | Edgar E. Iglesias | static int uart_can_rx(void *opaque) |
183 | ee118d95 | Edgar E. Iglesias | { |
184 | ee118d95 | Edgar E. Iglesias | struct xlx_uartlite *s = opaque;
|
185 | ee118d95 | Edgar E. Iglesias | int r;
|
186 | ee118d95 | Edgar E. Iglesias | |
187 | ee118d95 | Edgar E. Iglesias | r = s->rx_fifo_len < sizeof(s->rx_fifo);
|
188 | ee118d95 | Edgar E. Iglesias | if (!r)
|
189 | ee118d95 | Edgar E. Iglesias | printf("cannot receive!\n");
|
190 | ee118d95 | Edgar E. Iglesias | return r;
|
191 | ee118d95 | Edgar E. Iglesias | } |
192 | ee118d95 | Edgar E. Iglesias | |
193 | ee118d95 | Edgar E. Iglesias | static void uart_event(void *opaque, int event) |
194 | ee118d95 | Edgar E. Iglesias | { |
195 | ee118d95 | Edgar E. Iglesias | |
196 | ee118d95 | Edgar E. Iglesias | } |
197 | ee118d95 | Edgar E. Iglesias | |
198 | 81a322d4 | Gerd Hoffmann | static int xilinx_uartlite_init(SysBusDevice *dev) |
199 | ee118d95 | Edgar E. Iglesias | { |
200 | ee118d95 | Edgar E. Iglesias | struct xlx_uartlite *s = FROM_SYSBUS(typeof (*s), dev);
|
201 | ee118d95 | Edgar E. Iglesias | |
202 | ee118d95 | Edgar E. Iglesias | sysbus_init_irq(dev, &s->irq); |
203 | ee118d95 | Edgar E. Iglesias | |
204 | ee118d95 | Edgar E. Iglesias | uart_update_status(s); |
205 | 23d6055e | Peter A. G. Crosthwaite | memory_region_init_io(&s->mmio, &uart_ops, s, "xlnx.xps-uartlite",
|
206 | 23d6055e | Peter A. G. Crosthwaite | R_MAX * 4);
|
207 | 750ecd44 | Avi Kivity | sysbus_init_mmio(dev, &s->mmio); |
208 | ee118d95 | Edgar E. Iglesias | |
209 | 0beb4942 | Anthony Liguori | s->chr = qemu_char_get_next_serial(); |
210 | ee118d95 | Edgar E. Iglesias | if (s->chr)
|
211 | ee118d95 | Edgar E. Iglesias | qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); |
212 | 81a322d4 | Gerd Hoffmann | return 0; |
213 | ee118d95 | Edgar E. Iglesias | } |
214 | ee118d95 | Edgar E. Iglesias | |
215 | 999e12bb | Anthony Liguori | static void xilinx_uartlite_class_init(ObjectClass *klass, void *data) |
216 | 999e12bb | Anthony Liguori | { |
217 | 999e12bb | Anthony Liguori | SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); |
218 | 999e12bb | Anthony Liguori | |
219 | 999e12bb | Anthony Liguori | sdc->init = xilinx_uartlite_init; |
220 | 999e12bb | Anthony Liguori | } |
221 | 999e12bb | Anthony Liguori | |
222 | 39bffca2 | Anthony Liguori | static TypeInfo xilinx_uartlite_info = {
|
223 | 23d6055e | Peter A. G. Crosthwaite | .name = "xlnx.xps-uartlite",
|
224 | 39bffca2 | Anthony Liguori | .parent = TYPE_SYS_BUS_DEVICE, |
225 | 39bffca2 | Anthony Liguori | .instance_size = sizeof (struct xlx_uartlite), |
226 | 39bffca2 | Anthony Liguori | .class_init = xilinx_uartlite_class_init, |
227 | 999e12bb | Anthony Liguori | }; |
228 | 999e12bb | Anthony Liguori | |
229 | 83f7d43a | Andreas Färber | static void xilinx_uart_register_types(void) |
230 | ee118d95 | Edgar E. Iglesias | { |
231 | 39bffca2 | Anthony Liguori | type_register_static(&xilinx_uartlite_info); |
232 | ee118d95 | Edgar E. Iglesias | } |
233 | ee118d95 | Edgar E. Iglesias | |
234 | 83f7d43a | Andreas Färber | type_init(xilinx_uart_register_types) |