]> git.ipfire.org Git - thirdparty/qemu.git/blame - hw/char/grlib_apbuart.c
Include hw/irq.h a lot less
[thirdparty/qemu.git] / hw / char / grlib_apbuart.c
CommitLineData
8b1e1320
FC
1/*
2 * QEMU GRLIB APB UART Emulator
3 *
b70447aa 4 * Copyright (c) 2010-2019 AdaCore
8b1e1320
FC
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
db5ebe5f 25#include "qemu/osdep.h"
64552b6b 26#include "hw/irq.h"
b70447aa 27#include "hw/sparc/grlib.h"
83c9f4ca 28#include "hw/sysbus.h"
0b8fa32f 29#include "qemu/module.h"
4d43a603 30#include "chardev/char-fe.h"
8b1e1320
FC
31
32#include "trace.h"
33
34#define UART_REG_SIZE 20 /* Size of memory mapped registers */
35
36/* UART status register fields */
37#define UART_DATA_READY (1 << 0)
38#define UART_TRANSMIT_SHIFT_EMPTY (1 << 1)
39#define UART_TRANSMIT_FIFO_EMPTY (1 << 2)
40#define UART_BREAK_RECEIVED (1 << 3)
41#define UART_OVERRUN (1 << 4)
42#define UART_PARITY_ERROR (1 << 5)
43#define UART_FRAMING_ERROR (1 << 6)
44#define UART_TRANSMIT_FIFO_HALF (1 << 7)
45#define UART_RECEIVE_FIFO_HALF (1 << 8)
46#define UART_TRANSMIT_FIFO_FULL (1 << 9)
47#define UART_RECEIVE_FIFO_FULL (1 << 10)
48
49/* UART control register fields */
50#define UART_RECEIVE_ENABLE (1 << 0)
51#define UART_TRANSMIT_ENABLE (1 << 1)
52#define UART_RECEIVE_INTERRUPT (1 << 2)
53#define UART_TRANSMIT_INTERRUPT (1 << 3)
54#define UART_PARITY_SELECT (1 << 4)
55#define UART_PARITY_ENABLE (1 << 5)
56#define UART_FLOW_CONTROL (1 << 6)
57#define UART_LOOPBACK (1 << 7)
58#define UART_EXTERNAL_CLOCK (1 << 8)
59#define UART_RECEIVE_FIFO_INTERRUPT (1 << 9)
60#define UART_TRANSMIT_FIFO_INTERRUPT (1 << 10)
61#define UART_FIFO_DEBUG_MODE (1 << 11)
62#define UART_OUTPUT_ENABLE (1 << 12)
63#define UART_FIFO_AVAILABLE (1 << 31)
64
65/* Memory mapped register offsets */
66#define DATA_OFFSET 0x00
67#define STATUS_OFFSET 0x04
68#define CONTROL_OFFSET 0x08
69#define SCALER_OFFSET 0x0C /* not supported */
70#define FIFO_DEBUG_OFFSET 0x10 /* not supported */
71
0c685d28
FC
72#define FIFO_LENGTH 1024
73
ae8e0490
AF
74#define GRLIB_APB_UART(obj) \
75 OBJECT_CHECK(UART, (obj), TYPE_GRLIB_APB_UART)
76
8b1e1320 77typedef struct UART {
ae8e0490
AF
78 SysBusDevice parent_obj;
79
6281f7d1 80 MemoryRegion iomem;
8b1e1320
FC
81 qemu_irq irq;
82
becdfa00 83 CharBackend chr;
8b1e1320
FC
84
85 /* registers */
8b1e1320
FC
86 uint32_t status;
87 uint32_t control;
0c685d28
FC
88
89 /* FIFO */
90 char buffer[FIFO_LENGTH];
91 int len;
92 int current;
8b1e1320
FC
93} UART;
94
0c685d28
FC
95static int uart_data_to_read(UART *uart)
96{
97 return uart->current < uart->len;
98}
99
100static char uart_pop(UART *uart)
101{
102 char ret;
103
104 if (uart->len == 0) {
105 uart->status &= ~UART_DATA_READY;
106 return 0;
107 }
108
109 ret = uart->buffer[uart->current++];
110
111 if (uart->current >= uart->len) {
112 /* Flush */
113 uart->len = 0;
114 uart->current = 0;
115 }
116
117 if (!uart_data_to_read(uart)) {
118 uart->status &= ~UART_DATA_READY;
119 }
120
121 return ret;
122}
123
124static void uart_add_to_fifo(UART *uart,
125 const uint8_t *buffer,
126 int length)
127{
128 if (uart->len + length > FIFO_LENGTH) {
129 abort();
130 }
131 memcpy(uart->buffer + uart->len, buffer, length);
132 uart->len += length;
133}
134
8b1e1320
FC
135static int grlib_apbuart_can_receive(void *opaque)
136{
137 UART *uart = opaque;
138
0c685d28 139 return FIFO_LENGTH - uart->len;
8b1e1320
FC
140}
141
142static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size)
143{
144 UART *uart = opaque;
145
99e44800
RH
146 if (uart->control & UART_RECEIVE_ENABLE) {
147 uart_add_to_fifo(uart, buf, size);
0c685d28 148
99e44800 149 uart->status |= UART_DATA_READY;
8b1e1320 150
99e44800
RH
151 if (uart->control & UART_RECEIVE_INTERRUPT) {
152 qemu_irq_pulse(uart->irq);
153 }
8b1e1320
FC
154 }
155}
156
157static void grlib_apbuart_event(void *opaque, int event)
158{
159 trace_grlib_apbuart_event(event);
160}
161
0c685d28 162
a8170e5e 163static uint64_t grlib_apbuart_read(void *opaque, hwaddr addr,
0c685d28
FC
164 unsigned size)
165{
166 UART *uart = opaque;
167
168 addr &= 0xff;
169
170 /* Unit registers */
171 switch (addr) {
172 case DATA_OFFSET:
173 case DATA_OFFSET + 3: /* when only one byte read */
174 return uart_pop(uart);
175
176 case STATUS_OFFSET:
177 /* Read Only */
178 return uart->status;
179
180 case CONTROL_OFFSET:
181 return uart->control;
182
183 case SCALER_OFFSET:
184 /* Not supported */
185 return 0;
186
187 default:
188 trace_grlib_apbuart_readl_unknown(addr);
189 return 0;
190 }
191}
192
a8170e5e 193static void grlib_apbuart_write(void *opaque, hwaddr addr,
0c685d28 194 uint64_t value, unsigned size)
8b1e1320
FC
195{
196 UART *uart = opaque;
197 unsigned char c = 0;
198
199 addr &= 0xff;
200
201 /* Unit registers */
202 switch (addr) {
203 case DATA_OFFSET:
0c685d28 204 case DATA_OFFSET + 3: /* When only one byte write */
99e44800 205 /* Transmit when character device available and transmitter enabled */
30650701 206 if (qemu_chr_fe_backend_connected(&uart->chr) &&
5345fdb4 207 (uart->control & UART_TRANSMIT_ENABLE)) {
99e44800 208 c = value & 0xFF;
6ab3fc32
DB
209 /* XXX this blocks entire thread. Rewrite to use
210 * qemu_chr_fe_write and background I/O callbacks */
5345fdb4 211 qemu_chr_fe_write_all(&uart->chr, &c, 1);
99e44800
RH
212 /* Generate interrupt */
213 if (uart->control & UART_TRANSMIT_INTERRUPT) {
214 qemu_irq_pulse(uart->irq);
215 }
216 }
8b1e1320
FC
217 return;
218
219 case STATUS_OFFSET:
220 /* Read Only */
221 return;
222
223 case CONTROL_OFFSET:
0c685d28 224 uart->control = value;
8b1e1320
FC
225 return;
226
227 case SCALER_OFFSET:
228 /* Not supported */
229 return;
230
231 default:
232 break;
233 }
234
b4548fcc 235 trace_grlib_apbuart_writel_unknown(addr, value);
8b1e1320
FC
236}
237
6281f7d1 238static const MemoryRegionOps grlib_apbuart_ops = {
0c685d28
FC
239 .write = grlib_apbuart_write,
240 .read = grlib_apbuart_read,
6281f7d1 241 .endianness = DEVICE_NATIVE_ENDIAN,
8b1e1320
FC
242};
243
ddaa6e04 244static void grlib_apbuart_realize(DeviceState *dev, Error **errp)
8b1e1320 245{
ae8e0490 246 UART *uart = GRLIB_APB_UART(dev);
ddaa6e04 247 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
8b1e1320 248
5345fdb4
MAL
249 qemu_chr_fe_set_handlers(&uart->chr,
250 grlib_apbuart_can_receive,
251 grlib_apbuart_receive,
252 grlib_apbuart_event,
81517ba3 253 NULL, uart, NULL, true);
8b1e1320 254
ddaa6e04 255 sysbus_init_irq(sbd, &uart->irq);
8b1e1320 256
300b1fc6 257 memory_region_init_io(&uart->iomem, OBJECT(uart), &grlib_apbuart_ops, uart,
6281f7d1 258 "uart", UART_REG_SIZE);
8b1e1320 259
ddaa6e04 260 sysbus_init_mmio(sbd, &uart->iomem);
8b1e1320
FC
261}
262
99e44800
RH
263static void grlib_apbuart_reset(DeviceState *d)
264{
ae8e0490 265 UART *uart = GRLIB_APB_UART(d);
99e44800
RH
266
267 /* Transmitter FIFO and shift registers are always empty in QEMU */
268 uart->status = UART_TRANSMIT_FIFO_EMPTY | UART_TRANSMIT_SHIFT_EMPTY;
269 /* Everything is off */
270 uart->control = 0;
271 /* Flush receive FIFO */
272 uart->len = 0;
273 uart->current = 0;
274}
275
8eda2228 276static Property grlib_apbuart_properties[] = {
999e12bb
AL
277 DEFINE_PROP_CHR("chrdev", UART, chr),
278 DEFINE_PROP_END_OF_LIST(),
279};
280
8eda2228 281static void grlib_apbuart_class_init(ObjectClass *klass, void *data)
999e12bb 282{
39bffca2 283 DeviceClass *dc = DEVICE_CLASS(klass);
999e12bb 284
ddaa6e04 285 dc->realize = grlib_apbuart_realize;
99e44800 286 dc->reset = grlib_apbuart_reset;
8eda2228 287 dc->props = grlib_apbuart_properties;
999e12bb
AL
288}
289
8eda2228 290static const TypeInfo grlib_apbuart_info = {
ae8e0490 291 .name = TYPE_GRLIB_APB_UART,
39bffca2
AL
292 .parent = TYPE_SYS_BUS_DEVICE,
293 .instance_size = sizeof(UART),
8eda2228 294 .class_init = grlib_apbuart_class_init,
8b1e1320
FC
295};
296
8eda2228 297static void grlib_apbuart_register_types(void)
8b1e1320 298{
8eda2228 299 type_register_static(&grlib_apbuart_info);
8b1e1320
FC
300}
301
8eda2228 302type_init(grlib_apbuart_register_types)