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