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