1*142593c9SAntony Pavlov /* 2*142593c9SAntony Pavlov * QEMU model of the Canon DIGIC UART block. 3*142593c9SAntony Pavlov * 4*142593c9SAntony Pavlov * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com> 5*142593c9SAntony Pavlov * 6*142593c9SAntony Pavlov * This model is based on reverse engineering efforts 7*142593c9SAntony Pavlov * made by CHDK (http://chdk.wikia.com) and 8*142593c9SAntony Pavlov * Magic Lantern (http://www.magiclantern.fm) projects 9*142593c9SAntony Pavlov * contributors. 10*142593c9SAntony Pavlov * 11*142593c9SAntony Pavlov * See "Serial terminal" docs here: 12*142593c9SAntony Pavlov * http://magiclantern.wikia.com/wiki/Register_Map#Misc_Registers 13*142593c9SAntony Pavlov * 14*142593c9SAntony Pavlov * The QEMU model of the Milkymist UART block by Michael Walle 15*142593c9SAntony Pavlov * is used as a template. 16*142593c9SAntony Pavlov * 17*142593c9SAntony Pavlov * This program is free software; you can redistribute it and/or modify 18*142593c9SAntony Pavlov * it under the terms of the GNU General Public License as published by 19*142593c9SAntony Pavlov * the Free Software Foundation; either version 2 of the License, or 20*142593c9SAntony Pavlov * (at your option) any later version. 21*142593c9SAntony Pavlov * 22*142593c9SAntony Pavlov * This program is distributed in the hope that it will be useful, 23*142593c9SAntony Pavlov * but WITHOUT ANY WARRANTY; without even the implied warranty of 24*142593c9SAntony Pavlov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25*142593c9SAntony Pavlov * GNU General Public License for more details. 26*142593c9SAntony Pavlov * 27*142593c9SAntony Pavlov */ 28*142593c9SAntony Pavlov 29*142593c9SAntony Pavlov #include "hw/hw.h" 30*142593c9SAntony Pavlov #include "hw/sysbus.h" 31*142593c9SAntony Pavlov #include "sysemu/char.h" 32*142593c9SAntony Pavlov 33*142593c9SAntony Pavlov #include "hw/char/digic-uart.h" 34*142593c9SAntony Pavlov 35*142593c9SAntony Pavlov enum { 36*142593c9SAntony Pavlov ST_RX_RDY = (1 << 0), 37*142593c9SAntony Pavlov ST_TX_RDY = (1 << 1), 38*142593c9SAntony Pavlov }; 39*142593c9SAntony Pavlov 40*142593c9SAntony Pavlov static uint64_t digic_uart_read(void *opaque, hwaddr addr, 41*142593c9SAntony Pavlov unsigned size) 42*142593c9SAntony Pavlov { 43*142593c9SAntony Pavlov DigicUartState *s = opaque; 44*142593c9SAntony Pavlov uint64_t ret = 0; 45*142593c9SAntony Pavlov 46*142593c9SAntony Pavlov addr >>= 2; 47*142593c9SAntony Pavlov 48*142593c9SAntony Pavlov switch (addr) { 49*142593c9SAntony Pavlov case R_RX: 50*142593c9SAntony Pavlov s->reg_st &= ~(ST_RX_RDY); 51*142593c9SAntony Pavlov ret = s->reg_rx; 52*142593c9SAntony Pavlov break; 53*142593c9SAntony Pavlov 54*142593c9SAntony Pavlov case R_ST: 55*142593c9SAntony Pavlov ret = s->reg_st; 56*142593c9SAntony Pavlov break; 57*142593c9SAntony Pavlov 58*142593c9SAntony Pavlov default: 59*142593c9SAntony Pavlov qemu_log_mask(LOG_UNIMP, 60*142593c9SAntony Pavlov "digic-uart: read access to unknown register 0x" 61*142593c9SAntony Pavlov TARGET_FMT_plx, addr << 2); 62*142593c9SAntony Pavlov } 63*142593c9SAntony Pavlov 64*142593c9SAntony Pavlov return ret; 65*142593c9SAntony Pavlov } 66*142593c9SAntony Pavlov 67*142593c9SAntony Pavlov static void digic_uart_write(void *opaque, hwaddr addr, uint64_t value, 68*142593c9SAntony Pavlov unsigned size) 69*142593c9SAntony Pavlov { 70*142593c9SAntony Pavlov DigicUartState *s = opaque; 71*142593c9SAntony Pavlov unsigned char ch = value; 72*142593c9SAntony Pavlov 73*142593c9SAntony Pavlov addr >>= 2; 74*142593c9SAntony Pavlov 75*142593c9SAntony Pavlov switch (addr) { 76*142593c9SAntony Pavlov case R_TX: 77*142593c9SAntony Pavlov if (s->chr) { 78*142593c9SAntony Pavlov qemu_chr_fe_write_all(s->chr, &ch, 1); 79*142593c9SAntony Pavlov } 80*142593c9SAntony Pavlov break; 81*142593c9SAntony Pavlov 82*142593c9SAntony Pavlov case R_ST: 83*142593c9SAntony Pavlov /* 84*142593c9SAntony Pavlov * Ignore write to R_ST. 85*142593c9SAntony Pavlov * 86*142593c9SAntony Pavlov * The point is that this register is actively used 87*142593c9SAntony Pavlov * during receiving and transmitting symbols, 88*142593c9SAntony Pavlov * but we don't know the function of most of bits. 89*142593c9SAntony Pavlov * 90*142593c9SAntony Pavlov * Ignoring writes to R_ST is only a simplification 91*142593c9SAntony Pavlov * of the model. It has no perceptible side effects 92*142593c9SAntony Pavlov * for existing guests. 93*142593c9SAntony Pavlov */ 94*142593c9SAntony Pavlov break; 95*142593c9SAntony Pavlov 96*142593c9SAntony Pavlov default: 97*142593c9SAntony Pavlov qemu_log_mask(LOG_UNIMP, 98*142593c9SAntony Pavlov "digic-uart: write access to unknown register 0x" 99*142593c9SAntony Pavlov TARGET_FMT_plx, addr << 2); 100*142593c9SAntony Pavlov } 101*142593c9SAntony Pavlov } 102*142593c9SAntony Pavlov 103*142593c9SAntony Pavlov static const MemoryRegionOps uart_mmio_ops = { 104*142593c9SAntony Pavlov .read = digic_uart_read, 105*142593c9SAntony Pavlov .write = digic_uart_write, 106*142593c9SAntony Pavlov .valid = { 107*142593c9SAntony Pavlov .min_access_size = 4, 108*142593c9SAntony Pavlov .max_access_size = 4, 109*142593c9SAntony Pavlov }, 110*142593c9SAntony Pavlov .endianness = DEVICE_NATIVE_ENDIAN, 111*142593c9SAntony Pavlov }; 112*142593c9SAntony Pavlov 113*142593c9SAntony Pavlov static int uart_can_rx(void *opaque) 114*142593c9SAntony Pavlov { 115*142593c9SAntony Pavlov DigicUartState *s = opaque; 116*142593c9SAntony Pavlov 117*142593c9SAntony Pavlov return !(s->reg_st & ST_RX_RDY); 118*142593c9SAntony Pavlov } 119*142593c9SAntony Pavlov 120*142593c9SAntony Pavlov static void uart_rx(void *opaque, const uint8_t *buf, int size) 121*142593c9SAntony Pavlov { 122*142593c9SAntony Pavlov DigicUartState *s = opaque; 123*142593c9SAntony Pavlov 124*142593c9SAntony Pavlov assert(uart_can_rx(opaque)); 125*142593c9SAntony Pavlov 126*142593c9SAntony Pavlov s->reg_st |= ST_RX_RDY; 127*142593c9SAntony Pavlov s->reg_rx = *buf; 128*142593c9SAntony Pavlov } 129*142593c9SAntony Pavlov 130*142593c9SAntony Pavlov static void uart_event(void *opaque, int event) 131*142593c9SAntony Pavlov { 132*142593c9SAntony Pavlov } 133*142593c9SAntony Pavlov 134*142593c9SAntony Pavlov static void digic_uart_reset(DeviceState *d) 135*142593c9SAntony Pavlov { 136*142593c9SAntony Pavlov DigicUartState *s = DIGIC_UART(d); 137*142593c9SAntony Pavlov 138*142593c9SAntony Pavlov s->reg_rx = 0; 139*142593c9SAntony Pavlov s->reg_st = ST_TX_RDY; 140*142593c9SAntony Pavlov } 141*142593c9SAntony Pavlov 142*142593c9SAntony Pavlov static void digic_uart_realize(DeviceState *dev, Error **errp) 143*142593c9SAntony Pavlov { 144*142593c9SAntony Pavlov DigicUartState *s = DIGIC_UART(dev); 145*142593c9SAntony Pavlov 146*142593c9SAntony Pavlov s->chr = qemu_char_get_next_serial(); 147*142593c9SAntony Pavlov if (s->chr) { 148*142593c9SAntony Pavlov qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); 149*142593c9SAntony Pavlov } 150*142593c9SAntony Pavlov } 151*142593c9SAntony Pavlov 152*142593c9SAntony Pavlov static void digic_uart_init(Object *obj) 153*142593c9SAntony Pavlov { 154*142593c9SAntony Pavlov DigicUartState *s = DIGIC_UART(obj); 155*142593c9SAntony Pavlov 156*142593c9SAntony Pavlov memory_region_init_io(&s->regs_region, OBJECT(s), &uart_mmio_ops, s, 157*142593c9SAntony Pavlov TYPE_DIGIC_UART, 0x18); 158*142593c9SAntony Pavlov sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->regs_region); 159*142593c9SAntony Pavlov } 160*142593c9SAntony Pavlov 161*142593c9SAntony Pavlov static const VMStateDescription vmstate_digic_uart = { 162*142593c9SAntony Pavlov .name = "digic-uart", 163*142593c9SAntony Pavlov .version_id = 1, 164*142593c9SAntony Pavlov .minimum_version_id = 1, 165*142593c9SAntony Pavlov .minimum_version_id_old = 1, 166*142593c9SAntony Pavlov .fields = (VMStateField[]) { 167*142593c9SAntony Pavlov VMSTATE_UINT32(reg_rx, DigicUartState), 168*142593c9SAntony Pavlov VMSTATE_UINT32(reg_st, DigicUartState), 169*142593c9SAntony Pavlov VMSTATE_END_OF_LIST() 170*142593c9SAntony Pavlov } 171*142593c9SAntony Pavlov }; 172*142593c9SAntony Pavlov 173*142593c9SAntony Pavlov static void digic_uart_class_init(ObjectClass *klass, void *data) 174*142593c9SAntony Pavlov { 175*142593c9SAntony Pavlov DeviceClass *dc = DEVICE_CLASS(klass); 176*142593c9SAntony Pavlov 177*142593c9SAntony Pavlov dc->realize = digic_uart_realize; 178*142593c9SAntony Pavlov dc->reset = digic_uart_reset; 179*142593c9SAntony Pavlov dc->vmsd = &vmstate_digic_uart; 180*142593c9SAntony Pavlov } 181*142593c9SAntony Pavlov 182*142593c9SAntony Pavlov static const TypeInfo digic_uart_info = { 183*142593c9SAntony Pavlov .name = TYPE_DIGIC_UART, 184*142593c9SAntony Pavlov .parent = TYPE_SYS_BUS_DEVICE, 185*142593c9SAntony Pavlov .instance_size = sizeof(DigicUartState), 186*142593c9SAntony Pavlov .instance_init = digic_uart_init, 187*142593c9SAntony Pavlov .class_init = digic_uart_class_init, 188*142593c9SAntony Pavlov }; 189*142593c9SAntony Pavlov 190*142593c9SAntony Pavlov static void digic_uart_register_types(void) 191*142593c9SAntony Pavlov { 192*142593c9SAntony Pavlov type_register_static(&digic_uart_info); 193*142593c9SAntony Pavlov } 194*142593c9SAntony Pavlov 195*142593c9SAntony Pavlov type_init(digic_uart_register_types) 196