1 /*
2 * MAX78000 UART
3 *
4 * Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "qemu/osdep.h"
10 #include "hw/char/max78000_uart.h"
11 #include "hw/irq.h"
12 #include "hw/qdev-properties.h"
13 #include "hw/qdev-properties-system.h"
14 #include "qemu/log.h"
15 #include "qemu/module.h"
16 #include "migration/vmstate.h"
17 #include "trace.h"
18
19
max78000_uart_can_receive(void * opaque)20 static int max78000_uart_can_receive(void *opaque)
21 {
22 Max78000UartState *s = opaque;
23 if (!(s->ctrl & UART_BCLKEN)) {
24 return 0;
25 }
26 return fifo8_num_free(&s->rx_fifo);
27 }
28
max78000_update_irq(Max78000UartState * s)29 static void max78000_update_irq(Max78000UartState *s)
30 {
31 int interrupt_level;
32
33 interrupt_level = s->int_fl & s->int_en;
34 qemu_set_irq(s->irq, interrupt_level);
35 }
36
max78000_uart_receive(void * opaque,const uint8_t * buf,int size)37 static void max78000_uart_receive(void *opaque, const uint8_t *buf, int size)
38 {
39 Max78000UartState *s = opaque;
40
41 assert(size <= fifo8_num_free(&s->rx_fifo));
42
43 fifo8_push_all(&s->rx_fifo, buf, size);
44
45 uint32_t rx_threshold = s->ctrl & 0xf;
46
47 if (fifo8_num_used(&s->rx_fifo) >= rx_threshold) {
48 s->int_fl |= UART_RX_THD;
49 }
50
51 max78000_update_irq(s);
52 }
53
max78000_uart_reset_hold(Object * obj,ResetType type)54 static void max78000_uart_reset_hold(Object *obj, ResetType type)
55 {
56 Max78000UartState *s = MAX78000_UART(obj);
57
58 s->ctrl = 0;
59 s->status = UART_TX_EM | UART_RX_EM;
60 s->int_en = 0;
61 s->int_fl = 0;
62 s->osr = 0;
63 s->txpeek = 0;
64 s->pnr = UART_RTS;
65 s->fifo = 0;
66 s->dma = 0;
67 s->wken = 0;
68 s->wkfl = 0;
69 fifo8_reset(&s->rx_fifo);
70 }
71
max78000_uart_read(void * opaque,hwaddr addr,unsigned int size)72 static uint64_t max78000_uart_read(void *opaque, hwaddr addr,
73 unsigned int size)
74 {
75 Max78000UartState *s = opaque;
76 uint64_t retvalue = 0;
77 switch (addr) {
78 case UART_CTRL:
79 retvalue = s->ctrl;
80 break;
81 case UART_STATUS:
82 retvalue = (fifo8_num_used(&s->rx_fifo) << UART_RX_LVL) |
83 UART_TX_EM |
84 (fifo8_is_empty(&s->rx_fifo) ? UART_RX_EM : 0);
85 break;
86 case UART_INT_EN:
87 retvalue = s->int_en;
88 break;
89 case UART_INT_FL:
90 retvalue = s->int_fl;
91 break;
92 case UART_CLKDIV:
93 retvalue = s->clkdiv;
94 break;
95 case UART_OSR:
96 retvalue = s->osr;
97 break;
98 case UART_TXPEEK:
99 if (!fifo8_is_empty(&s->rx_fifo)) {
100 retvalue = fifo8_peek(&s->rx_fifo);
101 }
102 break;
103 case UART_PNR:
104 retvalue = s->pnr;
105 break;
106 case UART_FIFO:
107 if (!fifo8_is_empty(&s->rx_fifo)) {
108 retvalue = fifo8_pop(&s->rx_fifo);
109 max78000_update_irq(s);
110 }
111 break;
112 case UART_DMA:
113 /* DMA not implemented */
114 retvalue = s->dma;
115 break;
116 case UART_WKEN:
117 retvalue = s->wken;
118 break;
119 case UART_WKFL:
120 retvalue = s->wkfl;
121 break;
122 default:
123 qemu_log_mask(LOG_GUEST_ERROR,
124 "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
125 break;
126 }
127
128 return retvalue;
129 }
130
max78000_uart_write(void * opaque,hwaddr addr,uint64_t val64,unsigned int size)131 static void max78000_uart_write(void *opaque, hwaddr addr,
132 uint64_t val64, unsigned int size)
133 {
134 Max78000UartState *s = opaque;
135
136 uint32_t value = val64;
137 uint8_t data;
138
139 switch (addr) {
140 case UART_CTRL:
141 if (value & UART_FLUSH_RX) {
142 fifo8_reset(&s->rx_fifo);
143 }
144 if (value & UART_BCLKEN) {
145 value = value | UART_BCLKRDY;
146 }
147 s->ctrl = value & ~(UART_FLUSH_RX | UART_FLUSH_TX);
148
149 /*
150 * Software can manage UART flow control manually by setting hfc_en
151 * in UART_CTRL. This would require emulating uart at a lower level,
152 * and is currently unimplemented.
153 */
154
155 return;
156 case UART_STATUS:
157 /* UART_STATUS is read only */
158 return;
159 case UART_INT_EN:
160 s->int_en = value;
161 return;
162 case UART_INT_FL:
163 s->int_fl = s->int_fl & ~(value);
164 max78000_update_irq(s);
165 return;
166 case UART_CLKDIV:
167 s->clkdiv = value;
168 return;
169 case UART_OSR:
170 s->osr = value;
171 return;
172 case UART_PNR:
173 s->pnr = value;
174 return;
175 case UART_FIFO:
176 data = value & 0xff;
177 /*
178 * XXX this blocks entire thread. Rewrite to use
179 * qemu_chr_fe_write and background I/O callbacks
180 */
181 qemu_chr_fe_write_all(&s->chr, &data, 1);
182
183 /* TX is always empty */
184 s->int_fl |= UART_TX_HE;
185 max78000_update_irq(s);
186
187 return;
188 case UART_DMA:
189 /* DMA not implemented */
190 s->dma = value;
191 return;
192 case UART_WKEN:
193 s->wken = value;
194 return;
195 case UART_WKFL:
196 s->wkfl = value;
197 return;
198 default:
199 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
200 HWADDR_PRIx "\n", __func__, addr);
201 }
202 }
203
204 static const MemoryRegionOps max78000_uart_ops = {
205 .read = max78000_uart_read,
206 .write = max78000_uart_write,
207 .endianness = DEVICE_LITTLE_ENDIAN,
208 .valid.min_access_size = 4,
209 .valid.max_access_size = 4,
210 };
211
212 static const Property max78000_uart_properties[] = {
213 DEFINE_PROP_CHR("chardev", Max78000UartState, chr),
214 };
215
216 static const VMStateDescription max78000_uart_vmstate = {
217 .name = TYPE_MAX78000_UART,
218 .version_id = 1,
219 .minimum_version_id = 1,
220 .fields = (VMStateField[]) {
221 VMSTATE_UINT32(ctrl, Max78000UartState),
222 VMSTATE_UINT32(status, Max78000UartState),
223 VMSTATE_UINT32(int_en, Max78000UartState),
224 VMSTATE_UINT32(int_fl, Max78000UartState),
225 VMSTATE_UINT32(clkdiv, Max78000UartState),
226 VMSTATE_UINT32(osr, Max78000UartState),
227 VMSTATE_UINT32(txpeek, Max78000UartState),
228 VMSTATE_UINT32(pnr, Max78000UartState),
229 VMSTATE_UINT32(fifo, Max78000UartState),
230 VMSTATE_UINT32(dma, Max78000UartState),
231 VMSTATE_UINT32(wken, Max78000UartState),
232 VMSTATE_UINT32(wkfl, Max78000UartState),
233 VMSTATE_FIFO8(rx_fifo, Max78000UartState),
234 VMSTATE_END_OF_LIST()
235 }
236 };
237
max78000_uart_init(Object * obj)238 static void max78000_uart_init(Object *obj)
239 {
240 Max78000UartState *s = MAX78000_UART(obj);
241 fifo8_create(&s->rx_fifo, 8);
242
243 sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
244
245 memory_region_init_io(&s->mmio, obj, &max78000_uart_ops, s,
246 TYPE_MAX78000_UART, 0x400);
247 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
248 }
249
max78000_uart_realize(DeviceState * dev,Error ** errp)250 static void max78000_uart_realize(DeviceState *dev, Error **errp)
251 {
252 Max78000UartState *s = MAX78000_UART(dev);
253
254 qemu_chr_fe_set_handlers(&s->chr, max78000_uart_can_receive,
255 max78000_uart_receive, NULL, NULL,
256 s, NULL, true);
257 }
258
max78000_uart_class_init(ObjectClass * klass,const void * data)259 static void max78000_uart_class_init(ObjectClass *klass, const void *data)
260 {
261 DeviceClass *dc = DEVICE_CLASS(klass);
262 ResettableClass *rc = RESETTABLE_CLASS(klass);
263
264 rc->phases.hold = max78000_uart_reset_hold;
265
266 device_class_set_props(dc, max78000_uart_properties);
267 dc->realize = max78000_uart_realize;
268
269 dc->vmsd = &max78000_uart_vmstate;
270 }
271
272 static const TypeInfo max78000_uart_info = {
273 .name = TYPE_MAX78000_UART,
274 .parent = TYPE_SYS_BUS_DEVICE,
275 .instance_size = sizeof(Max78000UartState),
276 .instance_init = max78000_uart_init,
277 .class_init = max78000_uart_class_init,
278 };
279
max78000_uart_register_types(void)280 static void max78000_uart_register_types(void)
281 {
282 type_register_static(&max78000_uart_info);
283 }
284
285 type_init(max78000_uart_register_types)
286