xref: /illumos-kvm-cmd/hw/grlib_apbuart.c (revision 68396ea9)
1 /*
2  * QEMU GRLIB APB UART Emulator
3  *
4  * Copyright (c) 2010-2011 AdaCore
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 
25 #include "sysbus.h"
26 #include "qemu-char.h"
27 
28 #include "trace.h"
29 
30 #define UART_REG_SIZE 20     /* Size of memory mapped registers */
31 
32 /* UART status register fields */
33 #define UART_DATA_READY           (1 <<  0)
34 #define UART_TRANSMIT_SHIFT_EMPTY (1 <<  1)
35 #define UART_TRANSMIT_FIFO_EMPTY  (1 <<  2)
36 #define UART_BREAK_RECEIVED       (1 <<  3)
37 #define UART_OVERRUN              (1 <<  4)
38 #define UART_PARITY_ERROR         (1 <<  5)
39 #define UART_FRAMING_ERROR        (1 <<  6)
40 #define UART_TRANSMIT_FIFO_HALF   (1 <<  7)
41 #define UART_RECEIVE_FIFO_HALF    (1 <<  8)
42 #define UART_TRANSMIT_FIFO_FULL   (1 <<  9)
43 #define UART_RECEIVE_FIFO_FULL    (1 << 10)
44 
45 /* UART control register fields */
46 #define UART_RECEIVE_ENABLE          (1 <<  0)
47 #define UART_TRANSMIT_ENABLE         (1 <<  1)
48 #define UART_RECEIVE_INTERRUPT       (1 <<  2)
49 #define UART_TRANSMIT_INTERRUPT      (1 <<  3)
50 #define UART_PARITY_SELECT           (1 <<  4)
51 #define UART_PARITY_ENABLE           (1 <<  5)
52 #define UART_FLOW_CONTROL            (1 <<  6)
53 #define UART_LOOPBACK                (1 <<  7)
54 #define UART_EXTERNAL_CLOCK          (1 <<  8)
55 #define UART_RECEIVE_FIFO_INTERRUPT  (1 <<  9)
56 #define UART_TRANSMIT_FIFO_INTERRUPT (1 << 10)
57 #define UART_FIFO_DEBUG_MODE         (1 << 11)
58 #define UART_OUTPUT_ENABLE           (1 << 12)
59 #define UART_FIFO_AVAILABLE          (1 << 31)
60 
61 /* Memory mapped register offsets */
62 #define DATA_OFFSET       0x00
63 #define STATUS_OFFSET     0x04
64 #define CONTROL_OFFSET    0x08
65 #define SCALER_OFFSET     0x0C  /* not supported */
66 #define FIFO_DEBUG_OFFSET 0x10  /* not supported */
67 
68 typedef struct UART {
69     SysBusDevice busdev;
70 
71     qemu_irq irq;
72 
73     CharDriverState *chr;
74 
75     /* registers */
76     uint32_t receive;
77     uint32_t status;
78     uint32_t control;
79 } UART;
80 
grlib_apbuart_can_receive(void * opaque)81 static int grlib_apbuart_can_receive(void *opaque)
82 {
83     UART *uart = opaque;
84 
85     return !!(uart->status & UART_DATA_READY);
86 }
87 
grlib_apbuart_receive(void * opaque,const uint8_t * buf,int size)88 static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size)
89 {
90     UART *uart = opaque;
91 
92     uart->receive  = *buf;
93     uart->status  |= UART_DATA_READY;
94 
95     if (uart->control & UART_RECEIVE_INTERRUPT) {
96         qemu_irq_pulse(uart->irq);
97     }
98 }
99 
grlib_apbuart_event(void * opaque,int event)100 static void grlib_apbuart_event(void *opaque, int event)
101 {
102     trace_grlib_apbuart_event(event);
103 }
104 
105 static void
grlib_apbuart_writel(void * opaque,target_phys_addr_t addr,uint32_t value)106 grlib_apbuart_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
107 {
108     UART          *uart = opaque;
109     unsigned char  c    = 0;
110 
111     addr &= 0xff;
112 
113     /* Unit registers */
114     switch (addr) {
115     case DATA_OFFSET:
116         c = value & 0xFF;
117         qemu_chr_write(uart->chr, &c, 1);
118         return;
119 
120     case STATUS_OFFSET:
121         /* Read Only */
122         return;
123 
124     case CONTROL_OFFSET:
125         /* Not supported */
126         return;
127 
128     case SCALER_OFFSET:
129         /* Not supported */
130         return;
131 
132     default:
133         break;
134     }
135 
136     trace_grlib_apbuart_unknown_register("write", addr);
137 }
138 
139 static CPUReadMemoryFunc * const grlib_apbuart_read[] = {
140     NULL, NULL, NULL,
141 };
142 
143 static CPUWriteMemoryFunc * const grlib_apbuart_write[] = {
144     NULL, NULL, grlib_apbuart_writel,
145 };
146 
grlib_apbuart_init(SysBusDevice * dev)147 static int grlib_apbuart_init(SysBusDevice *dev)
148 {
149     UART *uart      = FROM_SYSBUS(typeof(*uart), dev);
150     int   uart_regs = 0;
151 
152     qemu_chr_add_handlers(uart->chr,
153                           grlib_apbuart_can_receive,
154                           grlib_apbuart_receive,
155                           grlib_apbuart_event,
156                           uart);
157 
158     sysbus_init_irq(dev, &uart->irq);
159 
160     uart_regs = cpu_register_io_memory(grlib_apbuart_read,
161                                        grlib_apbuart_write,
162                                        uart, DEVICE_NATIVE_ENDIAN);
163     if (uart_regs < 0) {
164         return -1;
165     }
166 
167     sysbus_init_mmio(dev, UART_REG_SIZE, uart_regs);
168 
169     return 0;
170 }
171 
172 static SysBusDeviceInfo grlib_gptimer_info = {
173     .init       = grlib_apbuart_init,
174     .qdev.name  = "grlib,apbuart",
175     .qdev.size  = sizeof(UART),
176     .qdev.props = (Property[]) {
177         DEFINE_PROP_CHR("chrdev", UART, chr),
178         DEFINE_PROP_END_OF_LIST()
179     }
180 };
181 
grlib_gptimer_register(void)182 static void grlib_gptimer_register(void)
183 {
184     sysbus_register_withprop(&grlib_gptimer_info);
185 }
186 
187 device_init(grlib_gptimer_register)
188