18b1e1320SFabien Chouteau /* 28b1e1320SFabien Chouteau * QEMU GRLIB APB UART Emulator 38b1e1320SFabien Chouteau * 4f432962eSClément Chigot * SPDX-License-Identifier: MIT 5f432962eSClément Chigot * 6f432962eSClément Chigot * Copyright (c) 2010-2024 AdaCore 78b1e1320SFabien Chouteau * 88b1e1320SFabien Chouteau * Permission is hereby granted, free of charge, to any person obtaining a copy 98b1e1320SFabien Chouteau * of this software and associated documentation files (the "Software"), to deal 108b1e1320SFabien Chouteau * in the Software without restriction, including without limitation the rights 118b1e1320SFabien Chouteau * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 128b1e1320SFabien Chouteau * copies of the Software, and to permit persons to whom the Software is 138b1e1320SFabien Chouteau * furnished to do so, subject to the following conditions: 148b1e1320SFabien Chouteau * 158b1e1320SFabien Chouteau * The above copyright notice and this permission notice shall be included in 168b1e1320SFabien Chouteau * all copies or substantial portions of the Software. 178b1e1320SFabien Chouteau * 188b1e1320SFabien Chouteau * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 198b1e1320SFabien Chouteau * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 208b1e1320SFabien Chouteau * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 218b1e1320SFabien Chouteau * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 228b1e1320SFabien Chouteau * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 238b1e1320SFabien Chouteau * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 248b1e1320SFabien Chouteau * THE SOFTWARE. 258b1e1320SFabien Chouteau */ 268b1e1320SFabien Chouteau 27db5ebe5fSPeter Maydell #include "qemu/osdep.h" 2864552b6bSMarkus Armbruster #include "hw/irq.h" 29a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 30ce35e229SEduardo Habkost #include "hw/qdev-properties-system.h" 31f432962eSClément Chigot #include "hw/char/grlib_uart.h" 3283c9f4caSPaolo Bonzini #include "hw/sysbus.h" 330b8fa32fSMarkus Armbruster #include "qemu/module.h" 344d43a603SMarc-André Lureau #include "chardev/char-fe.h" 358b1e1320SFabien Chouteau 368b1e1320SFabien Chouteau #include "trace.h" 37db1015e9SEduardo Habkost #include "qom/object.h" 388b1e1320SFabien Chouteau 398b1e1320SFabien Chouteau #define UART_REG_SIZE 20 /* Size of memory mapped registers */ 408b1e1320SFabien Chouteau 418b1e1320SFabien Chouteau /* UART status register fields */ 428b1e1320SFabien Chouteau #define UART_DATA_READY (1 << 0) 438b1e1320SFabien Chouteau #define UART_TRANSMIT_SHIFT_EMPTY (1 << 1) 448b1e1320SFabien Chouteau #define UART_TRANSMIT_FIFO_EMPTY (1 << 2) 458b1e1320SFabien Chouteau #define UART_BREAK_RECEIVED (1 << 3) 468b1e1320SFabien Chouteau #define UART_OVERRUN (1 << 4) 478b1e1320SFabien Chouteau #define UART_PARITY_ERROR (1 << 5) 488b1e1320SFabien Chouteau #define UART_FRAMING_ERROR (1 << 6) 498b1e1320SFabien Chouteau #define UART_TRANSMIT_FIFO_HALF (1 << 7) 508b1e1320SFabien Chouteau #define UART_RECEIVE_FIFO_HALF (1 << 8) 518b1e1320SFabien Chouteau #define UART_TRANSMIT_FIFO_FULL (1 << 9) 528b1e1320SFabien Chouteau #define UART_RECEIVE_FIFO_FULL (1 << 10) 538b1e1320SFabien Chouteau 548b1e1320SFabien Chouteau /* UART control register fields */ 558b1e1320SFabien Chouteau #define UART_RECEIVE_ENABLE (1 << 0) 568b1e1320SFabien Chouteau #define UART_TRANSMIT_ENABLE (1 << 1) 578b1e1320SFabien Chouteau #define UART_RECEIVE_INTERRUPT (1 << 2) 588b1e1320SFabien Chouteau #define UART_TRANSMIT_INTERRUPT (1 << 3) 598b1e1320SFabien Chouteau #define UART_PARITY_SELECT (1 << 4) 608b1e1320SFabien Chouteau #define UART_PARITY_ENABLE (1 << 5) 618b1e1320SFabien Chouteau #define UART_FLOW_CONTROL (1 << 6) 628b1e1320SFabien Chouteau #define UART_LOOPBACK (1 << 7) 638b1e1320SFabien Chouteau #define UART_EXTERNAL_CLOCK (1 << 8) 648b1e1320SFabien Chouteau #define UART_RECEIVE_FIFO_INTERRUPT (1 << 9) 658b1e1320SFabien Chouteau #define UART_TRANSMIT_FIFO_INTERRUPT (1 << 10) 668b1e1320SFabien Chouteau #define UART_FIFO_DEBUG_MODE (1 << 11) 678b1e1320SFabien Chouteau #define UART_OUTPUT_ENABLE (1 << 12) 688b1e1320SFabien Chouteau #define UART_FIFO_AVAILABLE (1 << 31) 698b1e1320SFabien Chouteau 708b1e1320SFabien Chouteau /* Memory mapped register offsets */ 718b1e1320SFabien Chouteau #define DATA_OFFSET 0x00 728b1e1320SFabien Chouteau #define STATUS_OFFSET 0x04 738b1e1320SFabien Chouteau #define CONTROL_OFFSET 0x08 748b1e1320SFabien Chouteau #define SCALER_OFFSET 0x0C /* not supported */ 758b1e1320SFabien Chouteau #define FIFO_DEBUG_OFFSET 0x10 /* not supported */ 768b1e1320SFabien Chouteau 770c685d28SFabien Chouteau #define FIFO_LENGTH 1024 780c685d28SFabien Chouteau 798063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(UART, GRLIB_APB_UART) 80ae8e0490SAndreas Färber 81db1015e9SEduardo Habkost struct UART { 82ae8e0490SAndreas Färber SysBusDevice parent_obj; 83ae8e0490SAndreas Färber 846281f7d1SAvi Kivity MemoryRegion iomem; 858b1e1320SFabien Chouteau qemu_irq irq; 868b1e1320SFabien Chouteau 87becdfa00SMarc-André Lureau CharBackend chr; 888b1e1320SFabien Chouteau 898b1e1320SFabien Chouteau /* registers */ 908b1e1320SFabien Chouteau uint32_t status; 918b1e1320SFabien Chouteau uint32_t control; 920c685d28SFabien Chouteau 930c685d28SFabien Chouteau /* FIFO */ 940c685d28SFabien Chouteau char buffer[FIFO_LENGTH]; 950c685d28SFabien Chouteau int len; 960c685d28SFabien Chouteau int current; 97db1015e9SEduardo Habkost }; 988b1e1320SFabien Chouteau 990c685d28SFabien Chouteau static int uart_data_to_read(UART *uart) 1000c685d28SFabien Chouteau { 1010c685d28SFabien Chouteau return uart->current < uart->len; 1020c685d28SFabien Chouteau } 1030c685d28SFabien Chouteau 1040c685d28SFabien Chouteau static char uart_pop(UART *uart) 1050c685d28SFabien Chouteau { 1060c685d28SFabien Chouteau char ret; 1070c685d28SFabien Chouteau 1080c685d28SFabien Chouteau if (uart->len == 0) { 1090c685d28SFabien Chouteau uart->status &= ~UART_DATA_READY; 1100c685d28SFabien Chouteau return 0; 1110c685d28SFabien Chouteau } 1120c685d28SFabien Chouteau 1130c685d28SFabien Chouteau ret = uart->buffer[uart->current++]; 1140c685d28SFabien Chouteau 1150c685d28SFabien Chouteau if (uart->current >= uart->len) { 1160c685d28SFabien Chouteau /* Flush */ 1170c685d28SFabien Chouteau uart->len = 0; 1180c685d28SFabien Chouteau uart->current = 0; 1190c685d28SFabien Chouteau } 1200c685d28SFabien Chouteau 1210c685d28SFabien Chouteau if (!uart_data_to_read(uart)) { 1220c685d28SFabien Chouteau uart->status &= ~UART_DATA_READY; 1230c685d28SFabien Chouteau } 1240c685d28SFabien Chouteau 1250c685d28SFabien Chouteau return ret; 1260c685d28SFabien Chouteau } 1270c685d28SFabien Chouteau 1280c685d28SFabien Chouteau static void uart_add_to_fifo(UART *uart, 1290c685d28SFabien Chouteau const uint8_t *buffer, 1300c685d28SFabien Chouteau int length) 1310c685d28SFabien Chouteau { 1320c685d28SFabien Chouteau if (uart->len + length > FIFO_LENGTH) { 1330c685d28SFabien Chouteau abort(); 1340c685d28SFabien Chouteau } 1350c685d28SFabien Chouteau memcpy(uart->buffer + uart->len, buffer, length); 1360c685d28SFabien Chouteau uart->len += length; 1370c685d28SFabien Chouteau } 1380c685d28SFabien Chouteau 1398b1e1320SFabien Chouteau static int grlib_apbuart_can_receive(void *opaque) 1408b1e1320SFabien Chouteau { 1418b1e1320SFabien Chouteau UART *uart = opaque; 1428b1e1320SFabien Chouteau 1430c685d28SFabien Chouteau return FIFO_LENGTH - uart->len; 1448b1e1320SFabien Chouteau } 1458b1e1320SFabien Chouteau 1468b1e1320SFabien Chouteau static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size) 1478b1e1320SFabien Chouteau { 1488b1e1320SFabien Chouteau UART *uart = opaque; 1498b1e1320SFabien Chouteau 15099e44800SRonald Hecht if (uart->control & UART_RECEIVE_ENABLE) { 1510c685d28SFabien Chouteau uart_add_to_fifo(uart, buf, size); 1520c685d28SFabien Chouteau 1538b1e1320SFabien Chouteau uart->status |= UART_DATA_READY; 1548b1e1320SFabien Chouteau 1558b1e1320SFabien Chouteau if (uart->control & UART_RECEIVE_INTERRUPT) { 1568b1e1320SFabien Chouteau qemu_irq_pulse(uart->irq); 1578b1e1320SFabien Chouteau } 1588b1e1320SFabien Chouteau } 15999e44800SRonald Hecht } 1608b1e1320SFabien Chouteau 161083b266fSPhilippe Mathieu-Daudé static void grlib_apbuart_event(void *opaque, QEMUChrEvent event) 1628b1e1320SFabien Chouteau { 1638b1e1320SFabien Chouteau trace_grlib_apbuart_event(event); 1648b1e1320SFabien Chouteau } 1658b1e1320SFabien Chouteau 1660c685d28SFabien Chouteau 167a8170e5eSAvi Kivity static uint64_t grlib_apbuart_read(void *opaque, hwaddr addr, 1680c685d28SFabien Chouteau unsigned size) 1690c685d28SFabien Chouteau { 1700c685d28SFabien Chouteau UART *uart = opaque; 1710c685d28SFabien Chouteau 1720c685d28SFabien Chouteau addr &= 0xff; 1730c685d28SFabien Chouteau 1740c685d28SFabien Chouteau /* Unit registers */ 1750c685d28SFabien Chouteau switch (addr) { 1760c685d28SFabien Chouteau case DATA_OFFSET: 1770c685d28SFabien Chouteau case DATA_OFFSET + 3: /* when only one byte read */ 1780c685d28SFabien Chouteau return uart_pop(uart); 1790c685d28SFabien Chouteau 1800c685d28SFabien Chouteau case STATUS_OFFSET: 1810c685d28SFabien Chouteau /* Read Only */ 1820c685d28SFabien Chouteau return uart->status; 1830c685d28SFabien Chouteau 1840c685d28SFabien Chouteau case CONTROL_OFFSET: 1850c685d28SFabien Chouteau return uart->control; 1860c685d28SFabien Chouteau 1870c685d28SFabien Chouteau case SCALER_OFFSET: 1880c685d28SFabien Chouteau /* Not supported */ 1890c685d28SFabien Chouteau return 0; 1900c685d28SFabien Chouteau 1910c685d28SFabien Chouteau default: 1920c685d28SFabien Chouteau trace_grlib_apbuart_readl_unknown(addr); 1930c685d28SFabien Chouteau return 0; 1940c685d28SFabien Chouteau } 1950c685d28SFabien Chouteau } 1960c685d28SFabien Chouteau 197a8170e5eSAvi Kivity static void grlib_apbuart_write(void *opaque, hwaddr addr, 1986281f7d1SAvi Kivity uint64_t value, unsigned size) 1998b1e1320SFabien Chouteau { 2008b1e1320SFabien Chouteau UART *uart = opaque; 2018b1e1320SFabien Chouteau unsigned char c = 0; 2028b1e1320SFabien Chouteau 2038b1e1320SFabien Chouteau addr &= 0xff; 2048b1e1320SFabien Chouteau 2058b1e1320SFabien Chouteau /* Unit registers */ 2068b1e1320SFabien Chouteau switch (addr) { 2078b1e1320SFabien Chouteau case DATA_OFFSET: 2080c685d28SFabien Chouteau case DATA_OFFSET + 3: /* When only one byte write */ 20999e44800SRonald Hecht /* Transmit when character device available and transmitter enabled */ 21030650701SAnton Nefedov if (qemu_chr_fe_backend_connected(&uart->chr) && 2115345fdb4SMarc-André Lureau (uart->control & UART_TRANSMIT_ENABLE)) { 2128b1e1320SFabien Chouteau c = value & 0xFF; 2136ab3fc32SDaniel P. Berrange /* XXX this blocks entire thread. Rewrite to use 2146ab3fc32SDaniel P. Berrange * qemu_chr_fe_write and background I/O callbacks */ 2155345fdb4SMarc-André Lureau qemu_chr_fe_write_all(&uart->chr, &c, 1); 21699e44800SRonald Hecht /* Generate interrupt */ 21799e44800SRonald Hecht if (uart->control & UART_TRANSMIT_INTERRUPT) { 21899e44800SRonald Hecht qemu_irq_pulse(uart->irq); 21999e44800SRonald Hecht } 22099e44800SRonald Hecht } 2218b1e1320SFabien Chouteau return; 2228b1e1320SFabien Chouteau 2238b1e1320SFabien Chouteau case STATUS_OFFSET: 2248b1e1320SFabien Chouteau /* Read Only */ 2258b1e1320SFabien Chouteau return; 2268b1e1320SFabien Chouteau 2278b1e1320SFabien Chouteau case CONTROL_OFFSET: 2280c685d28SFabien Chouteau uart->control = value; 2298b1e1320SFabien Chouteau return; 2308b1e1320SFabien Chouteau 2318b1e1320SFabien Chouteau case SCALER_OFFSET: 2328b1e1320SFabien Chouteau /* Not supported */ 2338b1e1320SFabien Chouteau return; 2348b1e1320SFabien Chouteau 2358b1e1320SFabien Chouteau default: 2368b1e1320SFabien Chouteau break; 2378b1e1320SFabien Chouteau } 2388b1e1320SFabien Chouteau 239b4548fccSStefan Hajnoczi trace_grlib_apbuart_writel_unknown(addr, value); 2408b1e1320SFabien Chouteau } 2418b1e1320SFabien Chouteau 2426281f7d1SAvi Kivity static const MemoryRegionOps grlib_apbuart_ops = { 2436281f7d1SAvi Kivity .write = grlib_apbuart_write, 2440c685d28SFabien Chouteau .read = grlib_apbuart_read, 2456281f7d1SAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 2468b1e1320SFabien Chouteau }; 2478b1e1320SFabien Chouteau 248ddaa6e04SMao Zhongyi static void grlib_apbuart_realize(DeviceState *dev, Error **errp) 2498b1e1320SFabien Chouteau { 250ae8e0490SAndreas Färber UART *uart = GRLIB_APB_UART(dev); 251ddaa6e04SMao Zhongyi SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 2528b1e1320SFabien Chouteau 2535345fdb4SMarc-André Lureau qemu_chr_fe_set_handlers(&uart->chr, 2548b1e1320SFabien Chouteau grlib_apbuart_can_receive, 2558b1e1320SFabien Chouteau grlib_apbuart_receive, 2568b1e1320SFabien Chouteau grlib_apbuart_event, 25781517ba3SAnton Nefedov NULL, uart, NULL, true); 2588b1e1320SFabien Chouteau 259ddaa6e04SMao Zhongyi sysbus_init_irq(sbd, &uart->irq); 2608b1e1320SFabien Chouteau 261300b1fc6SPaolo Bonzini memory_region_init_io(&uart->iomem, OBJECT(uart), &grlib_apbuart_ops, uart, 2626281f7d1SAvi Kivity "uart", UART_REG_SIZE); 2638b1e1320SFabien Chouteau 264ddaa6e04SMao Zhongyi sysbus_init_mmio(sbd, &uart->iomem); 2658b1e1320SFabien Chouteau } 2668b1e1320SFabien Chouteau 26799e44800SRonald Hecht static void grlib_apbuart_reset(DeviceState *d) 26899e44800SRonald Hecht { 269ae8e0490SAndreas Färber UART *uart = GRLIB_APB_UART(d); 27099e44800SRonald Hecht 27199e44800SRonald Hecht /* Transmitter FIFO and shift registers are always empty in QEMU */ 27299e44800SRonald Hecht uart->status = UART_TRANSMIT_FIFO_EMPTY | UART_TRANSMIT_SHIFT_EMPTY; 27399e44800SRonald Hecht /* Everything is off */ 27499e44800SRonald Hecht uart->control = 0; 27599e44800SRonald Hecht /* Flush receive FIFO */ 27699e44800SRonald Hecht uart->len = 0; 27799e44800SRonald Hecht uart->current = 0; 27899e44800SRonald Hecht } 27999e44800SRonald Hecht 2808eda2228SFabien Chouteau static Property grlib_apbuart_properties[] = { 2818b1e1320SFabien Chouteau DEFINE_PROP_CHR("chrdev", UART, chr), 282999e12bbSAnthony Liguori DEFINE_PROP_END_OF_LIST(), 283999e12bbSAnthony Liguori }; 284999e12bbSAnthony Liguori 2858eda2228SFabien Chouteau static void grlib_apbuart_class_init(ObjectClass *klass, void *data) 286999e12bbSAnthony Liguori { 28739bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 288999e12bbSAnthony Liguori 289ddaa6e04SMao Zhongyi dc->realize = grlib_apbuart_realize; 290*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, grlib_apbuart_reset); 2914f67d30bSMarc-André Lureau device_class_set_props(dc, grlib_apbuart_properties); 2928b1e1320SFabien Chouteau } 293999e12bbSAnthony Liguori 2948eda2228SFabien Chouteau static const TypeInfo grlib_apbuart_info = { 295ae8e0490SAndreas Färber .name = TYPE_GRLIB_APB_UART, 29639bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 29739bffca2SAnthony Liguori .instance_size = sizeof(UART), 2988eda2228SFabien Chouteau .class_init = grlib_apbuart_class_init, 2998b1e1320SFabien Chouteau }; 3008b1e1320SFabien Chouteau 3018eda2228SFabien Chouteau static void grlib_apbuart_register_types(void) 3028b1e1320SFabien Chouteau { 3038eda2228SFabien Chouteau type_register_static(&grlib_apbuart_info); 3048b1e1320SFabien Chouteau } 3058b1e1320SFabien Chouteau 3068eda2228SFabien Chouteau type_init(grlib_apbuart_register_types) 307