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/sysbus.h" 31d6454270SMarkus Armbruster #include "migration/vmstate.h" 324d43a603SMarc-André Lureau #include "chardev/char-fe.h" 3303dd024fSPaolo Bonzini #include "qemu/log.h" 340b8fa32fSMarkus Armbruster #include "qemu/module.h" 35142593c9SAntony Pavlov 36142593c9SAntony Pavlov #include "hw/char/digic-uart.h" 37*a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 38142593c9SAntony Pavlov 39142593c9SAntony Pavlov enum { 40142593c9SAntony Pavlov ST_RX_RDY = (1 << 0), 41142593c9SAntony Pavlov ST_TX_RDY = (1 << 1), 42142593c9SAntony Pavlov }; 43142593c9SAntony Pavlov 44142593c9SAntony Pavlov static uint64_t digic_uart_read(void *opaque, hwaddr addr, 45142593c9SAntony Pavlov unsigned size) 46142593c9SAntony Pavlov { 47142593c9SAntony Pavlov DigicUartState *s = opaque; 48142593c9SAntony Pavlov uint64_t ret = 0; 49142593c9SAntony Pavlov 50142593c9SAntony Pavlov addr >>= 2; 51142593c9SAntony Pavlov 52142593c9SAntony Pavlov switch (addr) { 53142593c9SAntony Pavlov case R_RX: 54142593c9SAntony Pavlov s->reg_st &= ~(ST_RX_RDY); 55142593c9SAntony Pavlov ret = s->reg_rx; 56142593c9SAntony Pavlov break; 57142593c9SAntony Pavlov 58142593c9SAntony Pavlov case R_ST: 59142593c9SAntony Pavlov ret = s->reg_st; 60142593c9SAntony Pavlov break; 61142593c9SAntony Pavlov 62142593c9SAntony Pavlov default: 63142593c9SAntony Pavlov qemu_log_mask(LOG_UNIMP, 64142593c9SAntony Pavlov "digic-uart: read access to unknown register 0x" 65428d42ceSPhilippe Mathieu-Daudé TARGET_FMT_plx "\n", addr << 2); 66142593c9SAntony Pavlov } 67142593c9SAntony Pavlov 68142593c9SAntony Pavlov return ret; 69142593c9SAntony Pavlov } 70142593c9SAntony Pavlov 71142593c9SAntony Pavlov static void digic_uart_write(void *opaque, hwaddr addr, uint64_t value, 72142593c9SAntony Pavlov unsigned size) 73142593c9SAntony Pavlov { 74142593c9SAntony Pavlov DigicUartState *s = opaque; 75142593c9SAntony Pavlov unsigned char ch = value; 76142593c9SAntony Pavlov 77142593c9SAntony Pavlov addr >>= 2; 78142593c9SAntony Pavlov 79142593c9SAntony Pavlov switch (addr) { 80142593c9SAntony Pavlov case R_TX: 816ab3fc32SDaniel P. Berrange /* XXX this blocks entire thread. Rewrite to use 826ab3fc32SDaniel P. Berrange * qemu_chr_fe_write and background I/O callbacks */ 835345fdb4SMarc-André Lureau qemu_chr_fe_write_all(&s->chr, &ch, 1); 84142593c9SAntony Pavlov break; 85142593c9SAntony Pavlov 86142593c9SAntony Pavlov case R_ST: 87142593c9SAntony Pavlov /* 88142593c9SAntony Pavlov * Ignore write to R_ST. 89142593c9SAntony Pavlov * 90142593c9SAntony Pavlov * The point is that this register is actively used 91142593c9SAntony Pavlov * during receiving and transmitting symbols, 92142593c9SAntony Pavlov * but we don't know the function of most of bits. 93142593c9SAntony Pavlov * 94142593c9SAntony Pavlov * Ignoring writes to R_ST is only a simplification 95142593c9SAntony Pavlov * of the model. It has no perceptible side effects 96142593c9SAntony Pavlov * for existing guests. 97142593c9SAntony Pavlov */ 98142593c9SAntony Pavlov break; 99142593c9SAntony Pavlov 100142593c9SAntony Pavlov default: 101142593c9SAntony Pavlov qemu_log_mask(LOG_UNIMP, 102142593c9SAntony Pavlov "digic-uart: write access to unknown register 0x" 103428d42ceSPhilippe Mathieu-Daudé TARGET_FMT_plx "\n", addr << 2); 104142593c9SAntony Pavlov } 105142593c9SAntony Pavlov } 106142593c9SAntony Pavlov 107142593c9SAntony Pavlov static const MemoryRegionOps uart_mmio_ops = { 108142593c9SAntony Pavlov .read = digic_uart_read, 109142593c9SAntony Pavlov .write = digic_uart_write, 110142593c9SAntony Pavlov .valid = { 111142593c9SAntony Pavlov .min_access_size = 4, 112142593c9SAntony Pavlov .max_access_size = 4, 113142593c9SAntony Pavlov }, 114142593c9SAntony Pavlov .endianness = DEVICE_NATIVE_ENDIAN, 115142593c9SAntony Pavlov }; 116142593c9SAntony Pavlov 117142593c9SAntony Pavlov static int uart_can_rx(void *opaque) 118142593c9SAntony Pavlov { 119142593c9SAntony Pavlov DigicUartState *s = opaque; 120142593c9SAntony Pavlov 121142593c9SAntony Pavlov return !(s->reg_st & ST_RX_RDY); 122142593c9SAntony Pavlov } 123142593c9SAntony Pavlov 124142593c9SAntony Pavlov static void uart_rx(void *opaque, const uint8_t *buf, int size) 125142593c9SAntony Pavlov { 126142593c9SAntony Pavlov DigicUartState *s = opaque; 127142593c9SAntony Pavlov 128142593c9SAntony Pavlov assert(uart_can_rx(opaque)); 129142593c9SAntony Pavlov 130142593c9SAntony Pavlov s->reg_st |= ST_RX_RDY; 131142593c9SAntony Pavlov s->reg_rx = *buf; 132142593c9SAntony Pavlov } 133142593c9SAntony Pavlov 134142593c9SAntony Pavlov static void uart_event(void *opaque, int event) 135142593c9SAntony Pavlov { 136142593c9SAntony Pavlov } 137142593c9SAntony Pavlov 138142593c9SAntony Pavlov static void digic_uart_reset(DeviceState *d) 139142593c9SAntony Pavlov { 140142593c9SAntony Pavlov DigicUartState *s = DIGIC_UART(d); 141142593c9SAntony Pavlov 142142593c9SAntony Pavlov s->reg_rx = 0; 143142593c9SAntony Pavlov s->reg_st = ST_TX_RDY; 144142593c9SAntony Pavlov } 145142593c9SAntony Pavlov 146142593c9SAntony Pavlov static void digic_uart_realize(DeviceState *dev, Error **errp) 147142593c9SAntony Pavlov { 148142593c9SAntony Pavlov DigicUartState *s = DIGIC_UART(dev); 149142593c9SAntony Pavlov 1505345fdb4SMarc-André Lureau qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, 15181517ba3SAnton Nefedov uart_event, NULL, s, NULL, true); 152142593c9SAntony Pavlov } 153142593c9SAntony Pavlov 154142593c9SAntony Pavlov static void digic_uart_init(Object *obj) 155142593c9SAntony Pavlov { 156142593c9SAntony Pavlov DigicUartState *s = DIGIC_UART(obj); 157142593c9SAntony Pavlov 158142593c9SAntony Pavlov memory_region_init_io(&s->regs_region, OBJECT(s), &uart_mmio_ops, s, 159142593c9SAntony Pavlov TYPE_DIGIC_UART, 0x18); 160142593c9SAntony Pavlov sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->regs_region); 161142593c9SAntony Pavlov } 162142593c9SAntony Pavlov 163142593c9SAntony Pavlov static const VMStateDescription vmstate_digic_uart = { 164142593c9SAntony Pavlov .name = "digic-uart", 165142593c9SAntony Pavlov .version_id = 1, 166142593c9SAntony Pavlov .minimum_version_id = 1, 167142593c9SAntony Pavlov .fields = (VMStateField[]) { 168142593c9SAntony Pavlov VMSTATE_UINT32(reg_rx, DigicUartState), 169142593c9SAntony Pavlov VMSTATE_UINT32(reg_st, DigicUartState), 170142593c9SAntony Pavlov VMSTATE_END_OF_LIST() 171142593c9SAntony Pavlov } 172142593c9SAntony Pavlov }; 173142593c9SAntony Pavlov 174746c3b3eSxiaoqiang zhao static Property digic_uart_properties[] = { 175746c3b3eSxiaoqiang zhao DEFINE_PROP_CHR("chardev", DigicUartState, chr), 176746c3b3eSxiaoqiang zhao DEFINE_PROP_END_OF_LIST(), 177746c3b3eSxiaoqiang zhao }; 178746c3b3eSxiaoqiang zhao 179142593c9SAntony Pavlov static void digic_uart_class_init(ObjectClass *klass, void *data) 180142593c9SAntony Pavlov { 181142593c9SAntony Pavlov DeviceClass *dc = DEVICE_CLASS(klass); 182142593c9SAntony Pavlov 183142593c9SAntony Pavlov dc->realize = digic_uart_realize; 184142593c9SAntony Pavlov dc->reset = digic_uart_reset; 185142593c9SAntony Pavlov dc->vmsd = &vmstate_digic_uart; 186746c3b3eSxiaoqiang zhao dc->props = digic_uart_properties; 187142593c9SAntony Pavlov } 188142593c9SAntony Pavlov 189142593c9SAntony Pavlov static const TypeInfo digic_uart_info = { 190142593c9SAntony Pavlov .name = TYPE_DIGIC_UART, 191142593c9SAntony Pavlov .parent = TYPE_SYS_BUS_DEVICE, 192142593c9SAntony Pavlov .instance_size = sizeof(DigicUartState), 193142593c9SAntony Pavlov .instance_init = digic_uart_init, 194142593c9SAntony Pavlov .class_init = digic_uart_class_init, 195142593c9SAntony Pavlov }; 196142593c9SAntony Pavlov 197142593c9SAntony Pavlov static void digic_uart_register_types(void) 198142593c9SAntony Pavlov { 199142593c9SAntony Pavlov type_register_static(&digic_uart_info); 200142593c9SAntony Pavlov } 201142593c9SAntony Pavlov 202142593c9SAntony Pavlov type_init(digic_uart_register_types) 203