2 * S5PC1XX UART Emulation
4 * Copyright (c) 2009 Samsung Electronics.
5 * Contributed by Kirill Batuzov <batuzovk@ispras.ru>
11 #include "s5pc1xx_gpio_regs.h"
14 #define QUEUE_SIZE 257
16 #define INT_RXD (1 << 0)
17 #define INT_ERROR (1 << 1)
18 #define INT_TXD (1 << 2)
19 #define INT_MODEM (1 << 3)
21 #define TRSTATUS_TRANSMITTER_READY (1 << 2)
22 #define TRSTATUS_BUFFER_EMPTY (1 << 1)
23 #define TRSTATUS_DATA_READY (1 << 0)
25 #define UFSTAT_RX_FIFO_FULL (1 << 8)
27 #define UFCON_FIFO_ENABLED (1 << 0)
28 #define UFCON_TX_LEVEL_SHIFT 8
29 #define UFCON_TX_LEVEL (7 << UFCON_TX_LEVEL_SHIFT)
31 #define UFSTAT_TX_COUNT_SHIT 16
32 #define UFSTAT_TX_COUNT (0xFF << UFSTAT_TX_COUNT_SHIT)
34 #define QI(x) ((x + 1) % QUEUE_SIZE)
35 #define QD(x) ((x - 1 + QUEUE_SIZE) % QUEUE_SIZE)
37 #define S5PC1XX_UART_REG_MEM_SIZE 0x3C
39 typedef struct UartQueue {
40 uint8_t queue[QUEUE_SIZE];
45 typedef struct S5pc1xxUartState {
72 static inline int queue_elem_count(const UartQueue *s)
77 return QUEUE_SIZE - s->s + s->t;
81 static inline int queue_empty_count(const UartQueue *s)
83 return s->size - queue_elem_count(s) - 1;
86 static inline int queue_empty(const UartQueue *s)
88 return (queue_elem_count(s) == 0);
91 static inline void queue_push(UartQueue *s, uint8_t x)
97 static inline uint8_t queue_get(UartQueue *s)
101 ret = s->queue[s->s];
106 static inline void queue_reset(UartQueue *s)
112 static void s5pc1xx_uart_update(S5pc1xxUartState *s)
114 if (s->ufcon && UFCON_FIFO_ENABLED) {
115 if (((s->ufstat && UFSTAT_TX_COUNT) >> UFSTAT_TX_COUNT_SHIT) <=
116 ((s->ufcon && UFCON_TX_LEVEL) >> UFCON_TX_LEVEL_SHIFT) * 2 ) {
117 s->uintsp |= INT_TXD;
121 s->uintp = s->uintsp & ~s->uintm;
123 qemu_irq_raise(s->irq);
125 qemu_irq_lower(s->irq);
129 /* Read UART by GPIO */
130 static uint32_t s5pc1xx_uart_gpio_read(void *opaque,
133 S5pc1xxUartState *s = (S5pc1xxUartState *)opaque;
135 /* TODO: check if s->uintp should be used instead of s->uintsp */
136 if (io_index == GPIO_UART_RXD(s->instance)) {
137 return (s->uintsp & INT_RXD);
139 if (io_index == GPIO_UART_TXD(s->instance)) {
140 return (s->uintsp & INT_TXD);
143 /* TODO: check if this is correct */
144 if (io_index == GPIO_UART_CTS(s->instance)) {
145 return ~(s->umstat & 0x1);
147 if (io_index == GPIO_UART_RTS(s->instance)) {
148 return ~(s->umcon & 0x1);
151 /* TODO: return correct values */
152 if (io_index == GPIO_UART_AUDIO_RXD) {
155 if (io_index == GPIO_UART_AUDIO_TXD) {
162 static GPIOReadMemoryFunc *s5pc1xx_uart_gpio_readfn = s5pc1xx_uart_gpio_read;
163 static GPIOWriteMemoryFunc *s5pc1xx_uart_gpio_writefn = s5pc1xx_empty_gpio_write; /* a gag */
165 static uint32_t s5pc1xx_uart_mm_read(void *opaque, target_phys_addr_t offset)
168 S5pc1xxUartState *s = (S5pc1xxUartState *)opaque;
186 s->ufstat = queue_elem_count(&s->rx) & 0xff;
187 if (queue_empty_count(&s->rx) == 0) {
188 s->ufstat |= UFSTAT_RX_FIFO_FULL;
195 if (! queue_empty(&s->rx)) {
196 res = queue_get(&s->rx);
197 if (queue_empty(&s->rx)) {
198 s->utrstat &= ~TRSTATUS_DATA_READY;
200 s->utrstat |= TRSTATUS_DATA_READY;
203 s->uintsp |= INT_ERROR;
204 s5pc1xx_uart_update(s);
208 s->utrstat &= ~TRSTATUS_DATA_READY;
223 hw_error("s5pc1xx.uart: bad read offset 0x" TARGET_FMT_plx "\n",
228 static void s5pc1xx_uart_mm_write(void *opaque, target_phys_addr_t offset,
232 S5pc1xxUartState *s = (S5pc1xxUartState *)opaque;
253 s->utrstat &= ~(TRSTATUS_TRANSMITTER_READY | TRSTATUS_BUFFER_EMPTY);
255 qemu_chr_write(s->chr, &ch, 1);
256 s->utrstat |= TRSTATUS_TRANSMITTER_READY | TRSTATUS_BUFFER_EMPTY;
257 s->uintsp |= INT_TXD;
268 s->uintsp &= ~val; /* TODO: does this really work in this way??? */
277 hw_error("s5pc1xx.uart: bad write offset 0x" TARGET_FMT_plx "\n",
280 s5pc1xx_uart_update(s);
283 CPUReadMemoryFunc * const s5pc1xx_uart_readfn[] = {
284 s5pc1xx_uart_mm_read,
285 s5pc1xx_uart_mm_read,
289 CPUWriteMemoryFunc * const s5pc1xx_uart_writefn[] = {
290 s5pc1xx_uart_mm_write,
291 s5pc1xx_uart_mm_write,
292 s5pc1xx_uart_mm_write
295 static void s5pc1xx_uart_save(QEMUFile *f, void *opaque)
297 S5pc1xxUartState *s = (S5pc1xxUartState *)opaque;
299 qemu_put_buffer(f, s->rx.queue, QUEUE_SIZE);
300 qemu_put_be32s(f, &s->rx.s);
301 qemu_put_be32s(f, &s->rx.t);
302 qemu_put_be32s(f, &s->rx.size);
304 qemu_put_be32s(f, &s->ulcon);
305 qemu_put_be32s(f, &s->ucon);
306 qemu_put_be32s(f, &s->ufcon);
307 qemu_put_be32s(f, &s->umcon);
308 qemu_put_be32s(f, &s->utrstat);
309 qemu_put_be32s(f, &s->uerstat);
310 qemu_put_be32s(f, &s->ufstat);
311 qemu_put_be32s(f, &s->umstat);
312 qemu_put_be32s(f, &s->utxh);
313 qemu_put_be32s(f, &s->urxh);
314 qemu_put_be32s(f, &s->ubrdiv);
315 qemu_put_be32s(f, &s->udivslot);
316 qemu_put_be32s(f, &s->uintp);
317 qemu_put_be32s(f, &s->uintsp);
318 qemu_put_be32s(f, &s->uintm);
321 static int s5pc1xx_uart_load(QEMUFile *f, void *opaque, int version_id)
323 S5pc1xxUartState *s = (S5pc1xxUartState *)opaque;
325 if (version_id != 1) {
329 qemu_get_buffer(f, s->rx.queue, QUEUE_SIZE);
330 qemu_get_be32s(f, &s->rx.s);
331 qemu_get_be32s(f, &s->rx.t);
332 qemu_get_be32s(f, &s->rx.size);
334 qemu_get_be32s(f, &s->ulcon);
335 qemu_get_be32s(f, &s->ucon);
336 qemu_get_be32s(f, &s->ufcon);
337 qemu_get_be32s(f, &s->umcon);
338 qemu_get_be32s(f, &s->utrstat);
339 qemu_get_be32s(f, &s->uerstat);
340 qemu_get_be32s(f, &s->ufstat);
341 qemu_get_be32s(f, &s->umstat);
342 qemu_get_be32s(f, &s->utxh);
343 qemu_get_be32s(f, &s->urxh);
344 qemu_get_be32s(f, &s->ubrdiv);
345 qemu_get_be32s(f, &s->udivslot);
346 qemu_get_be32s(f, &s->uintp);
347 qemu_get_be32s(f, &s->uintsp);
348 qemu_get_be32s(f, &s->uintm);
353 static int s5pc1xx_uart_can_receive(void *opaque)
355 S5pc1xxUartState *s = (S5pc1xxUartState *)opaque;
357 return queue_empty_count(&s->rx);
360 static void s5pc1xx_uart_trigger_level(S5pc1xxUartState *s)
363 if (! queue_empty(&s->rx)) {
364 s->uintsp |= INT_RXD;
368 static void s5pc1xx_uart_receive(void *opaque, const uint8_t *buf, int size)
371 S5pc1xxUartState *s = (S5pc1xxUartState *)opaque;
373 if (queue_empty_count(&s->rx) < size) {
374 for (i = 0; i < queue_empty_count(&s->rx); i++) {
375 queue_push(&s->rx, buf[i]);
377 s->uintp |= INT_ERROR;
378 s->utrstat |= TRSTATUS_DATA_READY;
380 for (i = 0; i < size; i++) {
381 queue_push(&s->rx, buf[i]);
383 s->utrstat |= TRSTATUS_DATA_READY;
385 s5pc1xx_uart_trigger_level(s);
388 s->uintsp |= INT_RXD;
389 s->utrstat |= TRSTATUS_DATA_READY;
391 s5pc1xx_uart_update(s);
394 static void s5pc1xx_uart_event(void *opaque, int event)
396 /* TODO: implement this */
399 static void s5pc1xx_uart_reset(DeviceState *d)
401 S5pc1xxUartState *s =
402 FROM_SYSBUS(S5pc1xxUartState, sysbus_from_qdev(d));
420 DeviceState *s5pc1xx_uart_init(target_phys_addr_t base, int instance,
421 int queue_size, qemu_irq irq,
422 CharDriverState *chr)
424 DeviceState *dev = qdev_create(NULL, "s5pc1xx.uart");
425 char str[] = "s5pc1xx.uart.00";
428 snprintf(str, strlen(str) + 1, "s5pc1xx.uart.%02d", instance % 100);
429 chr = qemu_chr_open(str, "null", NULL);
431 qdev_prop_set_chr(dev, "chr", chr);
432 qdev_prop_set_uint32(dev, "queue-size", queue_size);
433 qdev_prop_set_uint32(dev, "instance", instance);
434 qdev_init_nofail(dev);
435 sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
436 sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
440 static int s5pc1xx_uart_init1(SysBusDevice *dev)
443 S5pc1xxUartState *s = FROM_SYSBUS(S5pc1xxUartState, dev);
445 s5pc1xx_uart_reset(&s->busdev.qdev);
447 sysbus_init_irq(dev, &s->irq);
449 qemu_chr_add_handlers(s->chr, s5pc1xx_uart_can_receive,
450 s5pc1xx_uart_receive, s5pc1xx_uart_event, s);
453 cpu_register_io_memory(s5pc1xx_uart_readfn, s5pc1xx_uart_writefn, s,
454 DEVICE_NATIVE_ENDIAN);
455 sysbus_init_mmio(dev, S5PC1XX_UART_REG_MEM_SIZE, iomemtype);
457 s5pc1xx_gpio_register_io_memory(GPIO_IDX_UART, s->instance,
458 s5pc1xx_uart_gpio_readfn,
459 s5pc1xx_uart_gpio_writefn, NULL, s);
461 register_savevm(&dev->qdev, "s5pc1xx.uart", s->instance, 1,
462 s5pc1xx_uart_save, s5pc1xx_uart_load, s);
467 static SysBusDeviceInfo s5pc1xx_uart_info = {
468 .init = s5pc1xx_uart_init1,
469 .qdev.name = "s5pc1xx.uart",
470 .qdev.size = sizeof(S5pc1xxUartState),
471 .qdev.reset = s5pc1xx_uart_reset,
472 .qdev.props = (Property[]) {
473 DEFINE_PROP_UINT32("instance", S5pc1xxUartState, instance, 0),
474 DEFINE_PROP_UINT32("queue-size", S5pc1xxUartState, rx.size, 16),
475 DEFINE_PROP_CHR("chr", S5pc1xxUartState, chr),
476 DEFINE_PROP_END_OF_LIST(),
480 static void s5pc1xx_uart_register(void)
482 sysbus_register_withprop(&s5pc1xx_uart_info);
485 device_init(s5pc1xx_uart_register)