18b1e1320SFabien Chouteau /* 28b1e1320SFabien Chouteau * QEMU GRLIB APB UART Emulator 38b1e1320SFabien Chouteau * 48b1e1320SFabien Chouteau * Copyright (c) 2010-2011 AdaCore 58b1e1320SFabien Chouteau * 68b1e1320SFabien Chouteau * Permission is hereby granted, free of charge, to any person obtaining a copy 78b1e1320SFabien Chouteau * of this software and associated documentation files (the "Software"), to deal 88b1e1320SFabien Chouteau * in the Software without restriction, including without limitation the rights 98b1e1320SFabien Chouteau * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 108b1e1320SFabien Chouteau * copies of the Software, and to permit persons to whom the Software is 118b1e1320SFabien Chouteau * furnished to do so, subject to the following conditions: 128b1e1320SFabien Chouteau * 138b1e1320SFabien Chouteau * The above copyright notice and this permission notice shall be included in 148b1e1320SFabien Chouteau * all copies or substantial portions of the Software. 158b1e1320SFabien Chouteau * 168b1e1320SFabien Chouteau * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 178b1e1320SFabien Chouteau * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 188b1e1320SFabien Chouteau * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 198b1e1320SFabien Chouteau * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 208b1e1320SFabien Chouteau * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 218b1e1320SFabien Chouteau * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 228b1e1320SFabien Chouteau * THE SOFTWARE. 238b1e1320SFabien Chouteau */ 248b1e1320SFabien Chouteau 258b1e1320SFabien Chouteau #include "sysbus.h" 26927d4878SPaolo Bonzini #include "char/char.h" 278b1e1320SFabien Chouteau 288b1e1320SFabien Chouteau #include "trace.h" 298b1e1320SFabien Chouteau 308b1e1320SFabien Chouteau #define UART_REG_SIZE 20 /* Size of memory mapped registers */ 318b1e1320SFabien Chouteau 328b1e1320SFabien Chouteau /* UART status register fields */ 338b1e1320SFabien Chouteau #define UART_DATA_READY (1 << 0) 348b1e1320SFabien Chouteau #define UART_TRANSMIT_SHIFT_EMPTY (1 << 1) 358b1e1320SFabien Chouteau #define UART_TRANSMIT_FIFO_EMPTY (1 << 2) 368b1e1320SFabien Chouteau #define UART_BREAK_RECEIVED (1 << 3) 378b1e1320SFabien Chouteau #define UART_OVERRUN (1 << 4) 388b1e1320SFabien Chouteau #define UART_PARITY_ERROR (1 << 5) 398b1e1320SFabien Chouteau #define UART_FRAMING_ERROR (1 << 6) 408b1e1320SFabien Chouteau #define UART_TRANSMIT_FIFO_HALF (1 << 7) 418b1e1320SFabien Chouteau #define UART_RECEIVE_FIFO_HALF (1 << 8) 428b1e1320SFabien Chouteau #define UART_TRANSMIT_FIFO_FULL (1 << 9) 438b1e1320SFabien Chouteau #define UART_RECEIVE_FIFO_FULL (1 << 10) 448b1e1320SFabien Chouteau 458b1e1320SFabien Chouteau /* UART control register fields */ 468b1e1320SFabien Chouteau #define UART_RECEIVE_ENABLE (1 << 0) 478b1e1320SFabien Chouteau #define UART_TRANSMIT_ENABLE (1 << 1) 488b1e1320SFabien Chouteau #define UART_RECEIVE_INTERRUPT (1 << 2) 498b1e1320SFabien Chouteau #define UART_TRANSMIT_INTERRUPT (1 << 3) 508b1e1320SFabien Chouteau #define UART_PARITY_SELECT (1 << 4) 518b1e1320SFabien Chouteau #define UART_PARITY_ENABLE (1 << 5) 528b1e1320SFabien Chouteau #define UART_FLOW_CONTROL (1 << 6) 538b1e1320SFabien Chouteau #define UART_LOOPBACK (1 << 7) 548b1e1320SFabien Chouteau #define UART_EXTERNAL_CLOCK (1 << 8) 558b1e1320SFabien Chouteau #define UART_RECEIVE_FIFO_INTERRUPT (1 << 9) 568b1e1320SFabien Chouteau #define UART_TRANSMIT_FIFO_INTERRUPT (1 << 10) 578b1e1320SFabien Chouteau #define UART_FIFO_DEBUG_MODE (1 << 11) 588b1e1320SFabien Chouteau #define UART_OUTPUT_ENABLE (1 << 12) 598b1e1320SFabien Chouteau #define UART_FIFO_AVAILABLE (1 << 31) 608b1e1320SFabien Chouteau 618b1e1320SFabien Chouteau /* Memory mapped register offsets */ 628b1e1320SFabien Chouteau #define DATA_OFFSET 0x00 638b1e1320SFabien Chouteau #define STATUS_OFFSET 0x04 648b1e1320SFabien Chouteau #define CONTROL_OFFSET 0x08 658b1e1320SFabien Chouteau #define SCALER_OFFSET 0x0C /* not supported */ 668b1e1320SFabien Chouteau #define FIFO_DEBUG_OFFSET 0x10 /* not supported */ 678b1e1320SFabien Chouteau 680c685d28SFabien Chouteau #define FIFO_LENGTH 1024 690c685d28SFabien Chouteau 708b1e1320SFabien Chouteau typedef struct UART { 718b1e1320SFabien Chouteau SysBusDevice busdev; 726281f7d1SAvi Kivity MemoryRegion iomem; 738b1e1320SFabien Chouteau qemu_irq irq; 748b1e1320SFabien Chouteau 758b1e1320SFabien Chouteau CharDriverState *chr; 768b1e1320SFabien Chouteau 778b1e1320SFabien Chouteau /* registers */ 788b1e1320SFabien Chouteau uint32_t receive; 798b1e1320SFabien Chouteau uint32_t status; 808b1e1320SFabien Chouteau uint32_t control; 810c685d28SFabien Chouteau 820c685d28SFabien Chouteau /* FIFO */ 830c685d28SFabien Chouteau char buffer[FIFO_LENGTH]; 840c685d28SFabien Chouteau int len; 850c685d28SFabien Chouteau int current; 868b1e1320SFabien Chouteau } UART; 878b1e1320SFabien Chouteau 880c685d28SFabien Chouteau static int uart_data_to_read(UART *uart) 890c685d28SFabien Chouteau { 900c685d28SFabien Chouteau return uart->current < uart->len; 910c685d28SFabien Chouteau } 920c685d28SFabien Chouteau 930c685d28SFabien Chouteau static char uart_pop(UART *uart) 940c685d28SFabien Chouteau { 950c685d28SFabien Chouteau char ret; 960c685d28SFabien Chouteau 970c685d28SFabien Chouteau if (uart->len == 0) { 980c685d28SFabien Chouteau uart->status &= ~UART_DATA_READY; 990c685d28SFabien Chouteau return 0; 1000c685d28SFabien Chouteau } 1010c685d28SFabien Chouteau 1020c685d28SFabien Chouteau ret = uart->buffer[uart->current++]; 1030c685d28SFabien Chouteau 1040c685d28SFabien Chouteau if (uart->current >= uart->len) { 1050c685d28SFabien Chouteau /* Flush */ 1060c685d28SFabien Chouteau uart->len = 0; 1070c685d28SFabien Chouteau uart->current = 0; 1080c685d28SFabien Chouteau } 1090c685d28SFabien Chouteau 1100c685d28SFabien Chouteau if (!uart_data_to_read(uart)) { 1110c685d28SFabien Chouteau uart->status &= ~UART_DATA_READY; 1120c685d28SFabien Chouteau } 1130c685d28SFabien Chouteau 1140c685d28SFabien Chouteau return ret; 1150c685d28SFabien Chouteau } 1160c685d28SFabien Chouteau 1170c685d28SFabien Chouteau static void uart_add_to_fifo(UART *uart, 1180c685d28SFabien Chouteau const uint8_t *buffer, 1190c685d28SFabien Chouteau int length) 1200c685d28SFabien Chouteau { 1210c685d28SFabien Chouteau if (uart->len + length > FIFO_LENGTH) { 1220c685d28SFabien Chouteau abort(); 1230c685d28SFabien Chouteau } 1240c685d28SFabien Chouteau memcpy(uart->buffer + uart->len, buffer, length); 1250c685d28SFabien Chouteau uart->len += length; 1260c685d28SFabien Chouteau } 1270c685d28SFabien Chouteau 1288b1e1320SFabien Chouteau static int grlib_apbuart_can_receive(void *opaque) 1298b1e1320SFabien Chouteau { 1308b1e1320SFabien Chouteau UART *uart = opaque; 1318b1e1320SFabien Chouteau 1320c685d28SFabien Chouteau return FIFO_LENGTH - uart->len; 1338b1e1320SFabien Chouteau } 1348b1e1320SFabien Chouteau 1358b1e1320SFabien Chouteau static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size) 1368b1e1320SFabien Chouteau { 1378b1e1320SFabien Chouteau UART *uart = opaque; 1388b1e1320SFabien Chouteau 1390c685d28SFabien Chouteau uart_add_to_fifo(uart, buf, size); 1400c685d28SFabien Chouteau 1418b1e1320SFabien Chouteau uart->status |= UART_DATA_READY; 1428b1e1320SFabien Chouteau 1438b1e1320SFabien Chouteau if (uart->control & UART_RECEIVE_INTERRUPT) { 1448b1e1320SFabien Chouteau qemu_irq_pulse(uart->irq); 1458b1e1320SFabien Chouteau } 1468b1e1320SFabien Chouteau } 1478b1e1320SFabien Chouteau 1488b1e1320SFabien Chouteau static void grlib_apbuart_event(void *opaque, int event) 1498b1e1320SFabien Chouteau { 1508b1e1320SFabien Chouteau trace_grlib_apbuart_event(event); 1518b1e1320SFabien Chouteau } 1528b1e1320SFabien Chouteau 1530c685d28SFabien Chouteau 154a8170e5eSAvi Kivity static uint64_t grlib_apbuart_read(void *opaque, hwaddr addr, 1550c685d28SFabien Chouteau unsigned size) 1560c685d28SFabien Chouteau { 1570c685d28SFabien Chouteau UART *uart = opaque; 1580c685d28SFabien Chouteau 1590c685d28SFabien Chouteau addr &= 0xff; 1600c685d28SFabien Chouteau 1610c685d28SFabien Chouteau /* Unit registers */ 1620c685d28SFabien Chouteau switch (addr) { 1630c685d28SFabien Chouteau case DATA_OFFSET: 1640c685d28SFabien Chouteau case DATA_OFFSET + 3: /* when only one byte read */ 1650c685d28SFabien Chouteau return uart_pop(uart); 1660c685d28SFabien Chouteau 1670c685d28SFabien Chouteau case STATUS_OFFSET: 1680c685d28SFabien Chouteau /* Read Only */ 1690c685d28SFabien Chouteau return uart->status; 1700c685d28SFabien Chouteau 1710c685d28SFabien Chouteau case CONTROL_OFFSET: 1720c685d28SFabien Chouteau return uart->control; 1730c685d28SFabien Chouteau 1740c685d28SFabien Chouteau case SCALER_OFFSET: 1750c685d28SFabien Chouteau /* Not supported */ 1760c685d28SFabien Chouteau return 0; 1770c685d28SFabien Chouteau 1780c685d28SFabien Chouteau default: 1790c685d28SFabien Chouteau trace_grlib_apbuart_readl_unknown(addr); 1800c685d28SFabien Chouteau return 0; 1810c685d28SFabien Chouteau } 1820c685d28SFabien Chouteau } 1830c685d28SFabien Chouteau 184a8170e5eSAvi Kivity static void grlib_apbuart_write(void *opaque, hwaddr addr, 1856281f7d1SAvi Kivity uint64_t value, unsigned size) 1868b1e1320SFabien Chouteau { 1878b1e1320SFabien Chouteau UART *uart = opaque; 1888b1e1320SFabien Chouteau unsigned char c = 0; 1898b1e1320SFabien Chouteau 1908b1e1320SFabien Chouteau addr &= 0xff; 1918b1e1320SFabien Chouteau 1928b1e1320SFabien Chouteau /* Unit registers */ 1938b1e1320SFabien Chouteau switch (addr) { 1948b1e1320SFabien Chouteau case DATA_OFFSET: 1950c685d28SFabien Chouteau case DATA_OFFSET + 3: /* When only one byte write */ 1968b1e1320SFabien Chouteau c = value & 0xFF; 1972cc6e0a1SAnthony Liguori qemu_chr_fe_write(uart->chr, &c, 1); 1988b1e1320SFabien Chouteau return; 1998b1e1320SFabien Chouteau 2008b1e1320SFabien Chouteau case STATUS_OFFSET: 2018b1e1320SFabien Chouteau /* Read Only */ 2028b1e1320SFabien Chouteau return; 2038b1e1320SFabien Chouteau 2048b1e1320SFabien Chouteau case CONTROL_OFFSET: 2050c685d28SFabien Chouteau uart->control = value; 2068b1e1320SFabien Chouteau return; 2078b1e1320SFabien Chouteau 2088b1e1320SFabien Chouteau case SCALER_OFFSET: 2098b1e1320SFabien Chouteau /* Not supported */ 2108b1e1320SFabien Chouteau return; 2118b1e1320SFabien Chouteau 2128b1e1320SFabien Chouteau default: 2138b1e1320SFabien Chouteau break; 2148b1e1320SFabien Chouteau } 2158b1e1320SFabien Chouteau 216b4548fccSStefan Hajnoczi trace_grlib_apbuart_writel_unknown(addr, value); 2178b1e1320SFabien Chouteau } 2188b1e1320SFabien Chouteau 2196281f7d1SAvi Kivity static const MemoryRegionOps grlib_apbuart_ops = { 2206281f7d1SAvi Kivity .write = grlib_apbuart_write, 2210c685d28SFabien Chouteau .read = grlib_apbuart_read, 2226281f7d1SAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 2238b1e1320SFabien Chouteau }; 2248b1e1320SFabien Chouteau 2258b1e1320SFabien Chouteau static int grlib_apbuart_init(SysBusDevice *dev) 2268b1e1320SFabien Chouteau { 2278b1e1320SFabien Chouteau UART *uart = FROM_SYSBUS(typeof(*uart), dev); 2288b1e1320SFabien Chouteau 2298b1e1320SFabien Chouteau qemu_chr_add_handlers(uart->chr, 2308b1e1320SFabien Chouteau grlib_apbuart_can_receive, 2318b1e1320SFabien Chouteau grlib_apbuart_receive, 2328b1e1320SFabien Chouteau grlib_apbuart_event, 2338b1e1320SFabien Chouteau uart); 2348b1e1320SFabien Chouteau 2358b1e1320SFabien Chouteau sysbus_init_irq(dev, &uart->irq); 2368b1e1320SFabien Chouteau 2376281f7d1SAvi Kivity memory_region_init_io(&uart->iomem, &grlib_apbuart_ops, uart, 2386281f7d1SAvi Kivity "uart", UART_REG_SIZE); 2398b1e1320SFabien Chouteau 240750ecd44SAvi Kivity sysbus_init_mmio(dev, &uart->iomem); 2418b1e1320SFabien Chouteau 2428b1e1320SFabien Chouteau return 0; 2438b1e1320SFabien Chouteau } 2448b1e1320SFabien Chouteau 245*8eda2228SFabien Chouteau static Property grlib_apbuart_properties[] = { 2468b1e1320SFabien Chouteau DEFINE_PROP_CHR("chrdev", UART, chr), 247999e12bbSAnthony Liguori DEFINE_PROP_END_OF_LIST(), 248999e12bbSAnthony Liguori }; 249999e12bbSAnthony Liguori 250*8eda2228SFabien Chouteau static void grlib_apbuart_class_init(ObjectClass *klass, void *data) 251999e12bbSAnthony Liguori { 25239bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 253999e12bbSAnthony Liguori SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); 254999e12bbSAnthony Liguori 255999e12bbSAnthony Liguori k->init = grlib_apbuart_init; 256*8eda2228SFabien Chouteau dc->props = grlib_apbuart_properties; 2578b1e1320SFabien Chouteau } 258999e12bbSAnthony Liguori 259*8eda2228SFabien Chouteau static const TypeInfo grlib_apbuart_info = { 260999e12bbSAnthony Liguori .name = "grlib,apbuart", 26139bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 26239bffca2SAnthony Liguori .instance_size = sizeof(UART), 263*8eda2228SFabien Chouteau .class_init = grlib_apbuart_class_init, 2648b1e1320SFabien Chouteau }; 2658b1e1320SFabien Chouteau 266*8eda2228SFabien Chouteau static void grlib_apbuart_register_types(void) 2678b1e1320SFabien Chouteau { 268*8eda2228SFabien Chouteau type_register_static(&grlib_apbuart_info); 2698b1e1320SFabien Chouteau } 2708b1e1320SFabien Chouteau 271*8eda2228SFabien Chouteau type_init(grlib_apbuart_register_types) 272