1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include "qemu/osdep.h"
26#include "hw/irq.h"
27#include "hw/qdev-properties.h"
28#include "hw/qdev-properties-system.h"
29#include "hw/sparc/grlib.h"
30#include "hw/sysbus.h"
31#include "qemu/module.h"
32#include "chardev/char-fe.h"
33
34#include "trace.h"
35#include "qom/object.h"
36
37#define UART_REG_SIZE 20
38
39
40#define UART_DATA_READY (1 << 0)
41#define UART_TRANSMIT_SHIFT_EMPTY (1 << 1)
42#define UART_TRANSMIT_FIFO_EMPTY (1 << 2)
43#define UART_BREAK_RECEIVED (1 << 3)
44#define UART_OVERRUN (1 << 4)
45#define UART_PARITY_ERROR (1 << 5)
46#define UART_FRAMING_ERROR (1 << 6)
47#define UART_TRANSMIT_FIFO_HALF (1 << 7)
48#define UART_RECEIVE_FIFO_HALF (1 << 8)
49#define UART_TRANSMIT_FIFO_FULL (1 << 9)
50#define UART_RECEIVE_FIFO_FULL (1 << 10)
51
52
53#define UART_RECEIVE_ENABLE (1 << 0)
54#define UART_TRANSMIT_ENABLE (1 << 1)
55#define UART_RECEIVE_INTERRUPT (1 << 2)
56#define UART_TRANSMIT_INTERRUPT (1 << 3)
57#define UART_PARITY_SELECT (1 << 4)
58#define UART_PARITY_ENABLE (1 << 5)
59#define UART_FLOW_CONTROL (1 << 6)
60#define UART_LOOPBACK (1 << 7)
61#define UART_EXTERNAL_CLOCK (1 << 8)
62#define UART_RECEIVE_FIFO_INTERRUPT (1 << 9)
63#define UART_TRANSMIT_FIFO_INTERRUPT (1 << 10)
64#define UART_FIFO_DEBUG_MODE (1 << 11)
65#define UART_OUTPUT_ENABLE (1 << 12)
66#define UART_FIFO_AVAILABLE (1 << 31)
67
68
69#define DATA_OFFSET 0x00
70#define STATUS_OFFSET 0x04
71#define CONTROL_OFFSET 0x08
72#define SCALER_OFFSET 0x0C
73#define FIFO_DEBUG_OFFSET 0x10
74
75#define FIFO_LENGTH 1024
76
77OBJECT_DECLARE_SIMPLE_TYPE(UART, GRLIB_APB_UART)
78
79struct UART {
80 SysBusDevice parent_obj;
81
82 MemoryRegion iomem;
83 qemu_irq irq;
84
85 CharBackend chr;
86
87
88 uint32_t status;
89 uint32_t control;
90
91
92 char buffer[FIFO_LENGTH];
93 int len;
94 int current;
95};
96
97static int uart_data_to_read(UART *uart)
98{
99 return uart->current < uart->len;
100}
101
102static char uart_pop(UART *uart)
103{
104 char ret;
105
106 if (uart->len == 0) {
107 uart->status &= ~UART_DATA_READY;
108 return 0;
109 }
110
111 ret = uart->buffer[uart->current++];
112
113 if (uart->current >= uart->len) {
114
115 uart->len = 0;
116 uart->current = 0;
117 }
118
119 if (!uart_data_to_read(uart)) {
120 uart->status &= ~UART_DATA_READY;
121 }
122
123 return ret;
124}
125
126static void uart_add_to_fifo(UART *uart,
127 const uint8_t *buffer,
128 int length)
129{
130 if (uart->len + length > FIFO_LENGTH) {
131 abort();
132 }
133 memcpy(uart->buffer + uart->len, buffer, length);
134 uart->len += length;
135}
136
137static int grlib_apbuart_can_receive(void *opaque)
138{
139 UART *uart = opaque;
140
141 return FIFO_LENGTH - uart->len;
142}
143
144static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size)
145{
146 UART *uart = opaque;
147
148 if (uart->control & UART_RECEIVE_ENABLE) {
149 uart_add_to_fifo(uart, buf, size);
150
151 uart->status |= UART_DATA_READY;
152
153 if (uart->control & UART_RECEIVE_INTERRUPT) {
154 qemu_irq_pulse(uart->irq);
155 }
156 }
157}
158
159static void grlib_apbuart_event(void *opaque, QEMUChrEvent event)
160{
161 trace_grlib_apbuart_event(event);
162}
163
164
165static uint64_t grlib_apbuart_read(void *opaque, hwaddr addr,
166 unsigned size)
167{
168 UART *uart = opaque;
169
170 addr &= 0xff;
171
172
173 switch (addr) {
174 case DATA_OFFSET:
175 case DATA_OFFSET + 3:
176 return uart_pop(uart);
177
178 case STATUS_OFFSET:
179
180 return uart->status;
181
182 case CONTROL_OFFSET:
183 return uart->control;
184
185 case SCALER_OFFSET:
186
187 return 0;
188
189 default:
190 trace_grlib_apbuart_readl_unknown(addr);
191 return 0;
192 }
193}
194
195static void grlib_apbuart_write(void *opaque, hwaddr addr,
196 uint64_t value, unsigned size)
197{
198 UART *uart = opaque;
199 unsigned char c = 0;
200
201 addr &= 0xff;
202
203
204 switch (addr) {
205 case DATA_OFFSET:
206 case DATA_OFFSET + 3:
207
208 if (qemu_chr_fe_backend_connected(&uart->chr) &&
209 (uart->control & UART_TRANSMIT_ENABLE)) {
210 c = value & 0xFF;
211
212
213 qemu_chr_fe_write_all(&uart->chr, &c, 1);
214
215 if (uart->control & UART_TRANSMIT_INTERRUPT) {
216 qemu_irq_pulse(uart->irq);
217 }
218 }
219 return;
220
221 case STATUS_OFFSET:
222
223 return;
224
225 case CONTROL_OFFSET:
226 uart->control = value;
227 return;
228
229 case SCALER_OFFSET:
230
231 return;
232
233 default:
234 break;
235 }
236
237 trace_grlib_apbuart_writel_unknown(addr, value);
238}
239
240static const MemoryRegionOps grlib_apbuart_ops = {
241 .write = grlib_apbuart_write,
242 .read = grlib_apbuart_read,
243 .endianness = DEVICE_NATIVE_ENDIAN,
244};
245
246static void grlib_apbuart_realize(DeviceState *dev, Error **errp)
247{
248 UART *uart = GRLIB_APB_UART(dev);
249 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
250
251 qemu_chr_fe_set_handlers(&uart->chr,
252 grlib_apbuart_can_receive,
253 grlib_apbuart_receive,
254 grlib_apbuart_event,
255 NULL, uart, NULL, true);
256
257 sysbus_init_irq(sbd, &uart->irq);
258
259 memory_region_init_io(&uart->iomem, OBJECT(uart), &grlib_apbuart_ops, uart,
260 "uart", UART_REG_SIZE);
261
262 sysbus_init_mmio(sbd, &uart->iomem);
263}
264
265static void grlib_apbuart_reset(DeviceState *d)
266{
267 UART *uart = GRLIB_APB_UART(d);
268
269
270 uart->status = UART_TRANSMIT_FIFO_EMPTY | UART_TRANSMIT_SHIFT_EMPTY;
271
272 uart->control = 0;
273
274 uart->len = 0;
275 uart->current = 0;
276}
277
278static Property grlib_apbuart_properties[] = {
279 DEFINE_PROP_CHR("chrdev", UART, chr),
280 DEFINE_PROP_END_OF_LIST(),
281};
282
283static void grlib_apbuart_class_init(ObjectClass *klass, void *data)
284{
285 DeviceClass *dc = DEVICE_CLASS(klass);
286
287 dc->realize = grlib_apbuart_realize;
288 dc->reset = grlib_apbuart_reset;
289 device_class_set_props(dc, grlib_apbuart_properties);
290}
291
292static const TypeInfo grlib_apbuart_info = {
293 .name = TYPE_GRLIB_APB_UART,
294 .parent = TYPE_SYS_BUS_DEVICE,
295 .instance_size = sizeof(UART),
296 .class_init = grlib_apbuart_class_init,
297};
298
299static void grlib_apbuart_register_types(void)
300{
301 type_register_static(&grlib_apbuart_info);
302}
303
304type_init(grlib_apbuart_register_types)
305