1142593c9SAntony Pavlov /* 2142593c9SAntony Pavlov * QEMU model of the Canon DIGIC UART block. 3142593c9SAntony Pavlov * 4142593c9SAntony Pavlov * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com> 5142593c9SAntony Pavlov * 6142593c9SAntony Pavlov * This model is based on reverse engineering efforts 7142593c9SAntony Pavlov * made by CHDK (http://chdk.wikia.com) and 8142593c9SAntony Pavlov * Magic Lantern (http://www.magiclantern.fm) projects 9142593c9SAntony Pavlov * contributors. 10142593c9SAntony Pavlov * 11142593c9SAntony Pavlov * See "Serial terminal" docs here: 12142593c9SAntony Pavlov * http://magiclantern.wikia.com/wiki/Register_Map#Misc_Registers 13142593c9SAntony Pavlov * 14142593c9SAntony Pavlov * The QEMU model of the Milkymist UART block by Michael Walle 15142593c9SAntony Pavlov * is used as a template. 16142593c9SAntony Pavlov * 17142593c9SAntony Pavlov * This program is free software; you can redistribute it and/or modify 18142593c9SAntony Pavlov * it under the terms of the GNU General Public License as published by 19142593c9SAntony Pavlov * the Free Software Foundation; either version 2 of the License, or 20142593c9SAntony Pavlov * (at your option) any later version. 21142593c9SAntony Pavlov * 22142593c9SAntony Pavlov * This program is distributed in the hope that it will be useful, 23142593c9SAntony Pavlov * but WITHOUT ANY WARRANTY; without even the implied warranty of 24142593c9SAntony Pavlov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25142593c9SAntony Pavlov * GNU General Public License for more details. 26142593c9SAntony Pavlov * 27142593c9SAntony Pavlov */ 28142593c9SAntony Pavlov 298ef94f0bSPeter Maydell #include "qemu/osdep.h" 30142593c9SAntony Pavlov #include "hw/hw.h" 31142593c9SAntony Pavlov #include "hw/sysbus.h" 32142593c9SAntony Pavlov #include "sysemu/char.h" 33*03dd024fSPaolo Bonzini #include "qemu/log.h" 34142593c9SAntony Pavlov 35142593c9SAntony Pavlov #include "hw/char/digic-uart.h" 36142593c9SAntony Pavlov 37142593c9SAntony Pavlov enum { 38142593c9SAntony Pavlov ST_RX_RDY = (1 << 0), 39142593c9SAntony Pavlov ST_TX_RDY = (1 << 1), 40142593c9SAntony Pavlov }; 41142593c9SAntony Pavlov 42142593c9SAntony Pavlov static uint64_t digic_uart_read(void *opaque, hwaddr addr, 43142593c9SAntony Pavlov unsigned size) 44142593c9SAntony Pavlov { 45142593c9SAntony Pavlov DigicUartState *s = opaque; 46142593c9SAntony Pavlov uint64_t ret = 0; 47142593c9SAntony Pavlov 48142593c9SAntony Pavlov addr >>= 2; 49142593c9SAntony Pavlov 50142593c9SAntony Pavlov switch (addr) { 51142593c9SAntony Pavlov case R_RX: 52142593c9SAntony Pavlov s->reg_st &= ~(ST_RX_RDY); 53142593c9SAntony Pavlov ret = s->reg_rx; 54142593c9SAntony Pavlov break; 55142593c9SAntony Pavlov 56142593c9SAntony Pavlov case R_ST: 57142593c9SAntony Pavlov ret = s->reg_st; 58142593c9SAntony Pavlov break; 59142593c9SAntony Pavlov 60142593c9SAntony Pavlov default: 61142593c9SAntony Pavlov qemu_log_mask(LOG_UNIMP, 62142593c9SAntony Pavlov "digic-uart: read access to unknown register 0x" 63142593c9SAntony Pavlov TARGET_FMT_plx, addr << 2); 64142593c9SAntony Pavlov } 65142593c9SAntony Pavlov 66142593c9SAntony Pavlov return ret; 67142593c9SAntony Pavlov } 68142593c9SAntony Pavlov 69142593c9SAntony Pavlov static void digic_uart_write(void *opaque, hwaddr addr, uint64_t value, 70142593c9SAntony Pavlov unsigned size) 71142593c9SAntony Pavlov { 72142593c9SAntony Pavlov DigicUartState *s = opaque; 73142593c9SAntony Pavlov unsigned char ch = value; 74142593c9SAntony Pavlov 75142593c9SAntony Pavlov addr >>= 2; 76142593c9SAntony Pavlov 77142593c9SAntony Pavlov switch (addr) { 78142593c9SAntony Pavlov case R_TX: 79142593c9SAntony Pavlov if (s->chr) { 80142593c9SAntony Pavlov qemu_chr_fe_write_all(s->chr, &ch, 1); 81142593c9SAntony Pavlov } 82142593c9SAntony Pavlov break; 83142593c9SAntony Pavlov 84142593c9SAntony Pavlov case R_ST: 85142593c9SAntony Pavlov /* 86142593c9SAntony Pavlov * Ignore write to R_ST. 87142593c9SAntony Pavlov * 88142593c9SAntony Pavlov * The point is that this register is actively used 89142593c9SAntony Pavlov * during receiving and transmitting symbols, 90142593c9SAntony Pavlov * but we don't know the function of most of bits. 91142593c9SAntony Pavlov * 92142593c9SAntony Pavlov * Ignoring writes to R_ST is only a simplification 93142593c9SAntony Pavlov * of the model. It has no perceptible side effects 94142593c9SAntony Pavlov * for existing guests. 95142593c9SAntony Pavlov */ 96142593c9SAntony Pavlov break; 97142593c9SAntony Pavlov 98142593c9SAntony Pavlov default: 99142593c9SAntony Pavlov qemu_log_mask(LOG_UNIMP, 100142593c9SAntony Pavlov "digic-uart: write access to unknown register 0x" 101142593c9SAntony Pavlov TARGET_FMT_plx, addr << 2); 102142593c9SAntony Pavlov } 103142593c9SAntony Pavlov } 104142593c9SAntony Pavlov 105142593c9SAntony Pavlov static const MemoryRegionOps uart_mmio_ops = { 106142593c9SAntony Pavlov .read = digic_uart_read, 107142593c9SAntony Pavlov .write = digic_uart_write, 108142593c9SAntony Pavlov .valid = { 109142593c9SAntony Pavlov .min_access_size = 4, 110142593c9SAntony Pavlov .max_access_size = 4, 111142593c9SAntony Pavlov }, 112142593c9SAntony Pavlov .endianness = DEVICE_NATIVE_ENDIAN, 113142593c9SAntony Pavlov }; 114142593c9SAntony Pavlov 115142593c9SAntony Pavlov static int uart_can_rx(void *opaque) 116142593c9SAntony Pavlov { 117142593c9SAntony Pavlov DigicUartState *s = opaque; 118142593c9SAntony Pavlov 119142593c9SAntony Pavlov return !(s->reg_st & ST_RX_RDY); 120142593c9SAntony Pavlov } 121142593c9SAntony Pavlov 122142593c9SAntony Pavlov static void uart_rx(void *opaque, const uint8_t *buf, int size) 123142593c9SAntony Pavlov { 124142593c9SAntony Pavlov DigicUartState *s = opaque; 125142593c9SAntony Pavlov 126142593c9SAntony Pavlov assert(uart_can_rx(opaque)); 127142593c9SAntony Pavlov 128142593c9SAntony Pavlov s->reg_st |= ST_RX_RDY; 129142593c9SAntony Pavlov s->reg_rx = *buf; 130142593c9SAntony Pavlov } 131142593c9SAntony Pavlov 132142593c9SAntony Pavlov static void uart_event(void *opaque, int event) 133142593c9SAntony Pavlov { 134142593c9SAntony Pavlov } 135142593c9SAntony Pavlov 136142593c9SAntony Pavlov static void digic_uart_reset(DeviceState *d) 137142593c9SAntony Pavlov { 138142593c9SAntony Pavlov DigicUartState *s = DIGIC_UART(d); 139142593c9SAntony Pavlov 140142593c9SAntony Pavlov s->reg_rx = 0; 141142593c9SAntony Pavlov s->reg_st = ST_TX_RDY; 142142593c9SAntony Pavlov } 143142593c9SAntony Pavlov 144142593c9SAntony Pavlov static void digic_uart_realize(DeviceState *dev, Error **errp) 145142593c9SAntony Pavlov { 146142593c9SAntony Pavlov DigicUartState *s = DIGIC_UART(dev); 147142593c9SAntony Pavlov 148d71b22bbSMarkus Armbruster /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ 149142593c9SAntony Pavlov s->chr = qemu_char_get_next_serial(); 150142593c9SAntony Pavlov if (s->chr) { 151142593c9SAntony Pavlov qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); 152142593c9SAntony Pavlov } 153142593c9SAntony Pavlov } 154142593c9SAntony Pavlov 155142593c9SAntony Pavlov static void digic_uart_init(Object *obj) 156142593c9SAntony Pavlov { 157142593c9SAntony Pavlov DigicUartState *s = DIGIC_UART(obj); 158142593c9SAntony Pavlov 159142593c9SAntony Pavlov memory_region_init_io(&s->regs_region, OBJECT(s), &uart_mmio_ops, s, 160142593c9SAntony Pavlov TYPE_DIGIC_UART, 0x18); 161142593c9SAntony Pavlov sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->regs_region); 162142593c9SAntony Pavlov } 163142593c9SAntony Pavlov 164142593c9SAntony Pavlov static const VMStateDescription vmstate_digic_uart = { 165142593c9SAntony Pavlov .name = "digic-uart", 166142593c9SAntony Pavlov .version_id = 1, 167142593c9SAntony Pavlov .minimum_version_id = 1, 168142593c9SAntony Pavlov .fields = (VMStateField[]) { 169142593c9SAntony Pavlov VMSTATE_UINT32(reg_rx, DigicUartState), 170142593c9SAntony Pavlov VMSTATE_UINT32(reg_st, DigicUartState), 171142593c9SAntony Pavlov VMSTATE_END_OF_LIST() 172142593c9SAntony Pavlov } 173142593c9SAntony Pavlov }; 174142593c9SAntony Pavlov 175142593c9SAntony Pavlov static void digic_uart_class_init(ObjectClass *klass, void *data) 176142593c9SAntony Pavlov { 177142593c9SAntony Pavlov DeviceClass *dc = DEVICE_CLASS(klass); 178142593c9SAntony Pavlov 179142593c9SAntony Pavlov dc->realize = digic_uart_realize; 180142593c9SAntony Pavlov dc->reset = digic_uart_reset; 181142593c9SAntony Pavlov dc->vmsd = &vmstate_digic_uart; 1829f9bdf43SMarkus Armbruster /* Reason: realize() method uses qemu_char_get_next_serial() */ 1839f9bdf43SMarkus Armbruster dc->cannot_instantiate_with_device_add_yet = true; 184142593c9SAntony Pavlov } 185142593c9SAntony Pavlov 186142593c9SAntony Pavlov static const TypeInfo digic_uart_info = { 187142593c9SAntony Pavlov .name = TYPE_DIGIC_UART, 188142593c9SAntony Pavlov .parent = TYPE_SYS_BUS_DEVICE, 189142593c9SAntony Pavlov .instance_size = sizeof(DigicUartState), 190142593c9SAntony Pavlov .instance_init = digic_uart_init, 191142593c9SAntony Pavlov .class_init = digic_uart_class_init, 192142593c9SAntony Pavlov }; 193142593c9SAntony Pavlov 194142593c9SAntony Pavlov static void digic_uart_register_types(void) 195142593c9SAntony Pavlov { 196142593c9SAntony Pavlov type_register_static(&digic_uart_info); 197142593c9SAntony Pavlov } 198142593c9SAntony Pavlov 199142593c9SAntony Pavlov type_init(digic_uart_register_types) 200