1*429ca9d6SMichael Rolnik /* 2*429ca9d6SMichael Rolnik * AVR USART 3*429ca9d6SMichael Rolnik * 4*429ca9d6SMichael Rolnik * Copyright (c) 2018 University of Kent 5*429ca9d6SMichael Rolnik * Author: Sarah Harris 6*429ca9d6SMichael Rolnik * 7*429ca9d6SMichael Rolnik * This library is free software; you can redistribute it and/or 8*429ca9d6SMichael Rolnik * modify it under the terms of the GNU Lesser General Public 9*429ca9d6SMichael Rolnik * License as published by the Free Software Foundation; either 10*429ca9d6SMichael Rolnik * version 2.1 of the License, or (at your option) any later version. 11*429ca9d6SMichael Rolnik * 12*429ca9d6SMichael Rolnik * This library is distributed in the hope that it will be useful, 13*429ca9d6SMichael Rolnik * but WITHOUT ANY WARRANTY; without even the implied warranty of 14*429ca9d6SMichael Rolnik * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15*429ca9d6SMichael Rolnik * Lesser General Public License for more details. 16*429ca9d6SMichael Rolnik * 17*429ca9d6SMichael Rolnik * You should have received a copy of the GNU Lesser General Public 18*429ca9d6SMichael Rolnik * License along with this library; if not, see 19*429ca9d6SMichael Rolnik * <http://www.gnu.org/licenses/lgpl-2.1.html> 20*429ca9d6SMichael Rolnik */ 21*429ca9d6SMichael Rolnik 22*429ca9d6SMichael Rolnik #include "qemu/osdep.h" 23*429ca9d6SMichael Rolnik #include "hw/char/avr_usart.h" 24*429ca9d6SMichael Rolnik #include "qemu/log.h" 25*429ca9d6SMichael Rolnik #include "hw/irq.h" 26*429ca9d6SMichael Rolnik #include "hw/qdev-properties.h" 27*429ca9d6SMichael Rolnik 28*429ca9d6SMichael Rolnik static int avr_usart_can_receive(void *opaque) 29*429ca9d6SMichael Rolnik { 30*429ca9d6SMichael Rolnik AVRUsartState *usart = opaque; 31*429ca9d6SMichael Rolnik 32*429ca9d6SMichael Rolnik if (usart->data_valid || !(usart->csrb & USART_CSRB_RXEN)) { 33*429ca9d6SMichael Rolnik return 0; 34*429ca9d6SMichael Rolnik } 35*429ca9d6SMichael Rolnik return 1; 36*429ca9d6SMichael Rolnik } 37*429ca9d6SMichael Rolnik 38*429ca9d6SMichael Rolnik static void avr_usart_receive(void *opaque, const uint8_t *buffer, int size) 39*429ca9d6SMichael Rolnik { 40*429ca9d6SMichael Rolnik AVRUsartState *usart = opaque; 41*429ca9d6SMichael Rolnik assert(size == 1); 42*429ca9d6SMichael Rolnik assert(!usart->data_valid); 43*429ca9d6SMichael Rolnik usart->data = buffer[0]; 44*429ca9d6SMichael Rolnik usart->data_valid = true; 45*429ca9d6SMichael Rolnik usart->csra |= USART_CSRA_RXC; 46*429ca9d6SMichael Rolnik if (usart->csrb & USART_CSRB_RXCIE) { 47*429ca9d6SMichael Rolnik qemu_set_irq(usart->rxc_irq, 1); 48*429ca9d6SMichael Rolnik } 49*429ca9d6SMichael Rolnik } 50*429ca9d6SMichael Rolnik 51*429ca9d6SMichael Rolnik static void update_char_mask(AVRUsartState *usart) 52*429ca9d6SMichael Rolnik { 53*429ca9d6SMichael Rolnik uint8_t mode = ((usart->csrc & USART_CSRC_CSZ0) ? 1 : 0) | 54*429ca9d6SMichael Rolnik ((usart->csrc & USART_CSRC_CSZ1) ? 2 : 0) | 55*429ca9d6SMichael Rolnik ((usart->csrb & USART_CSRB_CSZ2) ? 4 : 0); 56*429ca9d6SMichael Rolnik switch (mode) { 57*429ca9d6SMichael Rolnik case 0: 58*429ca9d6SMichael Rolnik usart->char_mask = 0b11111; 59*429ca9d6SMichael Rolnik break; 60*429ca9d6SMichael Rolnik case 1: 61*429ca9d6SMichael Rolnik usart->char_mask = 0b111111; 62*429ca9d6SMichael Rolnik break; 63*429ca9d6SMichael Rolnik case 2: 64*429ca9d6SMichael Rolnik usart->char_mask = 0b1111111; 65*429ca9d6SMichael Rolnik break; 66*429ca9d6SMichael Rolnik case 3: 67*429ca9d6SMichael Rolnik usart->char_mask = 0b11111111; 68*429ca9d6SMichael Rolnik break; 69*429ca9d6SMichael Rolnik case 4: 70*429ca9d6SMichael Rolnik /* Fallthrough. */ 71*429ca9d6SMichael Rolnik case 5: 72*429ca9d6SMichael Rolnik /* Fallthrough. */ 73*429ca9d6SMichael Rolnik case 6: 74*429ca9d6SMichael Rolnik qemu_log_mask( 75*429ca9d6SMichael Rolnik LOG_GUEST_ERROR, 76*429ca9d6SMichael Rolnik "%s: Reserved character size 0x%x\n", 77*429ca9d6SMichael Rolnik __func__, 78*429ca9d6SMichael Rolnik mode); 79*429ca9d6SMichael Rolnik break; 80*429ca9d6SMichael Rolnik case 7: 81*429ca9d6SMichael Rolnik qemu_log_mask( 82*429ca9d6SMichael Rolnik LOG_GUEST_ERROR, 83*429ca9d6SMichael Rolnik "%s: Nine bit character size not supported (forcing eight)\n", 84*429ca9d6SMichael Rolnik __func__); 85*429ca9d6SMichael Rolnik usart->char_mask = 0b11111111; 86*429ca9d6SMichael Rolnik break; 87*429ca9d6SMichael Rolnik default: 88*429ca9d6SMichael Rolnik assert(0); 89*429ca9d6SMichael Rolnik } 90*429ca9d6SMichael Rolnik } 91*429ca9d6SMichael Rolnik 92*429ca9d6SMichael Rolnik static void avr_usart_reset(DeviceState *dev) 93*429ca9d6SMichael Rolnik { 94*429ca9d6SMichael Rolnik AVRUsartState *usart = AVR_USART(dev); 95*429ca9d6SMichael Rolnik usart->data_valid = false; 96*429ca9d6SMichael Rolnik usart->csra = 0b00100000; 97*429ca9d6SMichael Rolnik usart->csrb = 0b00000000; 98*429ca9d6SMichael Rolnik usart->csrc = 0b00000110; 99*429ca9d6SMichael Rolnik usart->brrl = 0; 100*429ca9d6SMichael Rolnik usart->brrh = 0; 101*429ca9d6SMichael Rolnik update_char_mask(usart); 102*429ca9d6SMichael Rolnik qemu_set_irq(usart->rxc_irq, 0); 103*429ca9d6SMichael Rolnik qemu_set_irq(usart->txc_irq, 0); 104*429ca9d6SMichael Rolnik qemu_set_irq(usart->dre_irq, 0); 105*429ca9d6SMichael Rolnik } 106*429ca9d6SMichael Rolnik 107*429ca9d6SMichael Rolnik static uint64_t avr_usart_read(void *opaque, hwaddr addr, unsigned int size) 108*429ca9d6SMichael Rolnik { 109*429ca9d6SMichael Rolnik AVRUsartState *usart = opaque; 110*429ca9d6SMichael Rolnik uint8_t data; 111*429ca9d6SMichael Rolnik assert(size == 1); 112*429ca9d6SMichael Rolnik 113*429ca9d6SMichael Rolnik if (!usart->enabled) { 114*429ca9d6SMichael Rolnik return 0; 115*429ca9d6SMichael Rolnik } 116*429ca9d6SMichael Rolnik 117*429ca9d6SMichael Rolnik switch (addr) { 118*429ca9d6SMichael Rolnik case USART_DR: 119*429ca9d6SMichael Rolnik if (!(usart->csrb & USART_CSRB_RXEN)) { 120*429ca9d6SMichael Rolnik /* Receiver disabled, ignore. */ 121*429ca9d6SMichael Rolnik return 0; 122*429ca9d6SMichael Rolnik } 123*429ca9d6SMichael Rolnik if (usart->data_valid) { 124*429ca9d6SMichael Rolnik data = usart->data & usart->char_mask; 125*429ca9d6SMichael Rolnik usart->data_valid = false; 126*429ca9d6SMichael Rolnik } else { 127*429ca9d6SMichael Rolnik data = 0; 128*429ca9d6SMichael Rolnik } 129*429ca9d6SMichael Rolnik usart->csra &= 0xff ^ USART_CSRA_RXC; 130*429ca9d6SMichael Rolnik qemu_set_irq(usart->rxc_irq, 0); 131*429ca9d6SMichael Rolnik qemu_chr_fe_accept_input(&usart->chr); 132*429ca9d6SMichael Rolnik return data; 133*429ca9d6SMichael Rolnik case USART_CSRA: 134*429ca9d6SMichael Rolnik return usart->csra; 135*429ca9d6SMichael Rolnik case USART_CSRB: 136*429ca9d6SMichael Rolnik return usart->csrb; 137*429ca9d6SMichael Rolnik case USART_CSRC: 138*429ca9d6SMichael Rolnik return usart->csrc; 139*429ca9d6SMichael Rolnik case USART_BRRL: 140*429ca9d6SMichael Rolnik return usart->brrl; 141*429ca9d6SMichael Rolnik case USART_BRRH: 142*429ca9d6SMichael Rolnik return usart->brrh; 143*429ca9d6SMichael Rolnik default: 144*429ca9d6SMichael Rolnik qemu_log_mask( 145*429ca9d6SMichael Rolnik LOG_GUEST_ERROR, 146*429ca9d6SMichael Rolnik "%s: Bad offset 0x%"HWADDR_PRIx"\n", 147*429ca9d6SMichael Rolnik __func__, 148*429ca9d6SMichael Rolnik addr); 149*429ca9d6SMichael Rolnik } 150*429ca9d6SMichael Rolnik return 0; 151*429ca9d6SMichael Rolnik } 152*429ca9d6SMichael Rolnik 153*429ca9d6SMichael Rolnik static void avr_usart_write(void *opaque, hwaddr addr, uint64_t value, 154*429ca9d6SMichael Rolnik unsigned int size) 155*429ca9d6SMichael Rolnik { 156*429ca9d6SMichael Rolnik AVRUsartState *usart = opaque; 157*429ca9d6SMichael Rolnik uint8_t mask; 158*429ca9d6SMichael Rolnik uint8_t data; 159*429ca9d6SMichael Rolnik assert((value & 0xff) == value); 160*429ca9d6SMichael Rolnik assert(size == 1); 161*429ca9d6SMichael Rolnik 162*429ca9d6SMichael Rolnik if (!usart->enabled) { 163*429ca9d6SMichael Rolnik return; 164*429ca9d6SMichael Rolnik } 165*429ca9d6SMichael Rolnik 166*429ca9d6SMichael Rolnik switch (addr) { 167*429ca9d6SMichael Rolnik case USART_DR: 168*429ca9d6SMichael Rolnik if (!(usart->csrb & USART_CSRB_TXEN)) { 169*429ca9d6SMichael Rolnik /* Transmitter disabled, ignore. */ 170*429ca9d6SMichael Rolnik return; 171*429ca9d6SMichael Rolnik } 172*429ca9d6SMichael Rolnik usart->csra |= USART_CSRA_TXC; 173*429ca9d6SMichael Rolnik usart->csra |= USART_CSRA_DRE; 174*429ca9d6SMichael Rolnik if (usart->csrb & USART_CSRB_TXCIE) { 175*429ca9d6SMichael Rolnik qemu_set_irq(usart->txc_irq, 1); 176*429ca9d6SMichael Rolnik usart->csra &= 0xff ^ USART_CSRA_TXC; 177*429ca9d6SMichael Rolnik } 178*429ca9d6SMichael Rolnik if (usart->csrb & USART_CSRB_DREIE) { 179*429ca9d6SMichael Rolnik qemu_set_irq(usart->dre_irq, 1); 180*429ca9d6SMichael Rolnik } 181*429ca9d6SMichael Rolnik data = value; 182*429ca9d6SMichael Rolnik qemu_chr_fe_write_all(&usart->chr, &data, 1); 183*429ca9d6SMichael Rolnik break; 184*429ca9d6SMichael Rolnik case USART_CSRA: 185*429ca9d6SMichael Rolnik mask = 0b01000011; 186*429ca9d6SMichael Rolnik /* Mask read-only bits. */ 187*429ca9d6SMichael Rolnik value = (value & mask) | (usart->csra & (0xff ^ mask)); 188*429ca9d6SMichael Rolnik usart->csra = value; 189*429ca9d6SMichael Rolnik if (value & USART_CSRA_TXC) { 190*429ca9d6SMichael Rolnik usart->csra ^= USART_CSRA_TXC; 191*429ca9d6SMichael Rolnik qemu_set_irq(usart->txc_irq, 0); 192*429ca9d6SMichael Rolnik } 193*429ca9d6SMichael Rolnik if (value & USART_CSRA_MPCM) { 194*429ca9d6SMichael Rolnik qemu_log_mask( 195*429ca9d6SMichael Rolnik LOG_GUEST_ERROR, 196*429ca9d6SMichael Rolnik "%s: MPCM not supported by USART\n", 197*429ca9d6SMichael Rolnik __func__); 198*429ca9d6SMichael Rolnik } 199*429ca9d6SMichael Rolnik break; 200*429ca9d6SMichael Rolnik case USART_CSRB: 201*429ca9d6SMichael Rolnik mask = 0b11111101; 202*429ca9d6SMichael Rolnik /* Mask read-only bits. */ 203*429ca9d6SMichael Rolnik value = (value & mask) | (usart->csrb & (0xff ^ mask)); 204*429ca9d6SMichael Rolnik usart->csrb = value; 205*429ca9d6SMichael Rolnik if (!(value & USART_CSRB_RXEN)) { 206*429ca9d6SMichael Rolnik /* Receiver disabled, flush input buffer. */ 207*429ca9d6SMichael Rolnik usart->data_valid = false; 208*429ca9d6SMichael Rolnik } 209*429ca9d6SMichael Rolnik qemu_set_irq(usart->rxc_irq, 210*429ca9d6SMichael Rolnik ((value & USART_CSRB_RXCIE) && 211*429ca9d6SMichael Rolnik (usart->csra & USART_CSRA_RXC)) ? 1 : 0); 212*429ca9d6SMichael Rolnik qemu_set_irq(usart->txc_irq, 213*429ca9d6SMichael Rolnik ((value & USART_CSRB_TXCIE) && 214*429ca9d6SMichael Rolnik (usart->csra & USART_CSRA_TXC)) ? 1 : 0); 215*429ca9d6SMichael Rolnik qemu_set_irq(usart->dre_irq, 216*429ca9d6SMichael Rolnik ((value & USART_CSRB_DREIE) && 217*429ca9d6SMichael Rolnik (usart->csra & USART_CSRA_DRE)) ? 1 : 0); 218*429ca9d6SMichael Rolnik update_char_mask(usart); 219*429ca9d6SMichael Rolnik break; 220*429ca9d6SMichael Rolnik case USART_CSRC: 221*429ca9d6SMichael Rolnik usart->csrc = value; 222*429ca9d6SMichael Rolnik if ((value & USART_CSRC_MSEL1) && (value & USART_CSRC_MSEL0)) { 223*429ca9d6SMichael Rolnik qemu_log_mask( 224*429ca9d6SMichael Rolnik LOG_GUEST_ERROR, 225*429ca9d6SMichael Rolnik "%s: SPI mode not supported by USART\n", 226*429ca9d6SMichael Rolnik __func__); 227*429ca9d6SMichael Rolnik } 228*429ca9d6SMichael Rolnik if ((value & USART_CSRC_MSEL1) && !(value & USART_CSRC_MSEL0)) { 229*429ca9d6SMichael Rolnik qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad USART mode\n", __func__); 230*429ca9d6SMichael Rolnik } 231*429ca9d6SMichael Rolnik if (!(value & USART_CSRC_PM1) && (value & USART_CSRC_PM0)) { 232*429ca9d6SMichael Rolnik qemu_log_mask( 233*429ca9d6SMichael Rolnik LOG_GUEST_ERROR, 234*429ca9d6SMichael Rolnik "%s: Bad USART parity mode\n", 235*429ca9d6SMichael Rolnik __func__); 236*429ca9d6SMichael Rolnik } 237*429ca9d6SMichael Rolnik update_char_mask(usart); 238*429ca9d6SMichael Rolnik break; 239*429ca9d6SMichael Rolnik case USART_BRRL: 240*429ca9d6SMichael Rolnik usart->brrl = value; 241*429ca9d6SMichael Rolnik break; 242*429ca9d6SMichael Rolnik case USART_BRRH: 243*429ca9d6SMichael Rolnik usart->brrh = value & 0b00001111; 244*429ca9d6SMichael Rolnik break; 245*429ca9d6SMichael Rolnik default: 246*429ca9d6SMichael Rolnik qemu_log_mask( 247*429ca9d6SMichael Rolnik LOG_GUEST_ERROR, 248*429ca9d6SMichael Rolnik "%s: Bad offset 0x%"HWADDR_PRIx"\n", 249*429ca9d6SMichael Rolnik __func__, 250*429ca9d6SMichael Rolnik addr); 251*429ca9d6SMichael Rolnik } 252*429ca9d6SMichael Rolnik } 253*429ca9d6SMichael Rolnik 254*429ca9d6SMichael Rolnik static const MemoryRegionOps avr_usart_ops = { 255*429ca9d6SMichael Rolnik .read = avr_usart_read, 256*429ca9d6SMichael Rolnik .write = avr_usart_write, 257*429ca9d6SMichael Rolnik .endianness = DEVICE_NATIVE_ENDIAN, 258*429ca9d6SMichael Rolnik .impl = {.min_access_size = 1, .max_access_size = 1} 259*429ca9d6SMichael Rolnik }; 260*429ca9d6SMichael Rolnik 261*429ca9d6SMichael Rolnik static Property avr_usart_properties[] = { 262*429ca9d6SMichael Rolnik DEFINE_PROP_CHR("chardev", AVRUsartState, chr), 263*429ca9d6SMichael Rolnik DEFINE_PROP_END_OF_LIST(), 264*429ca9d6SMichael Rolnik }; 265*429ca9d6SMichael Rolnik 266*429ca9d6SMichael Rolnik static void avr_usart_pr(void *opaque, int irq, int level) 267*429ca9d6SMichael Rolnik { 268*429ca9d6SMichael Rolnik AVRUsartState *s = AVR_USART(opaque); 269*429ca9d6SMichael Rolnik 270*429ca9d6SMichael Rolnik s->enabled = !level; 271*429ca9d6SMichael Rolnik 272*429ca9d6SMichael Rolnik if (!s->enabled) { 273*429ca9d6SMichael Rolnik avr_usart_reset(DEVICE(s)); 274*429ca9d6SMichael Rolnik } 275*429ca9d6SMichael Rolnik } 276*429ca9d6SMichael Rolnik 277*429ca9d6SMichael Rolnik static void avr_usart_init(Object *obj) 278*429ca9d6SMichael Rolnik { 279*429ca9d6SMichael Rolnik AVRUsartState *s = AVR_USART(obj); 280*429ca9d6SMichael Rolnik sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rxc_irq); 281*429ca9d6SMichael Rolnik sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->dre_irq); 282*429ca9d6SMichael Rolnik sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->txc_irq); 283*429ca9d6SMichael Rolnik memory_region_init_io(&s->mmio, obj, &avr_usart_ops, s, TYPE_AVR_USART, 7); 284*429ca9d6SMichael Rolnik sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 285*429ca9d6SMichael Rolnik qdev_init_gpio_in(DEVICE(s), avr_usart_pr, 1); 286*429ca9d6SMichael Rolnik s->enabled = true; 287*429ca9d6SMichael Rolnik } 288*429ca9d6SMichael Rolnik 289*429ca9d6SMichael Rolnik static void avr_usart_realize(DeviceState *dev, Error **errp) 290*429ca9d6SMichael Rolnik { 291*429ca9d6SMichael Rolnik AVRUsartState *s = AVR_USART(dev); 292*429ca9d6SMichael Rolnik qemu_chr_fe_set_handlers(&s->chr, avr_usart_can_receive, 293*429ca9d6SMichael Rolnik avr_usart_receive, NULL, NULL, 294*429ca9d6SMichael Rolnik s, NULL, true); 295*429ca9d6SMichael Rolnik avr_usart_reset(dev); 296*429ca9d6SMichael Rolnik } 297*429ca9d6SMichael Rolnik 298*429ca9d6SMichael Rolnik static void avr_usart_class_init(ObjectClass *klass, void *data) 299*429ca9d6SMichael Rolnik { 300*429ca9d6SMichael Rolnik DeviceClass *dc = DEVICE_CLASS(klass); 301*429ca9d6SMichael Rolnik 302*429ca9d6SMichael Rolnik dc->reset = avr_usart_reset; 303*429ca9d6SMichael Rolnik device_class_set_props(dc, avr_usart_properties); 304*429ca9d6SMichael Rolnik dc->realize = avr_usart_realize; 305*429ca9d6SMichael Rolnik } 306*429ca9d6SMichael Rolnik 307*429ca9d6SMichael Rolnik static const TypeInfo avr_usart_info = { 308*429ca9d6SMichael Rolnik .name = TYPE_AVR_USART, 309*429ca9d6SMichael Rolnik .parent = TYPE_SYS_BUS_DEVICE, 310*429ca9d6SMichael Rolnik .instance_size = sizeof(AVRUsartState), 311*429ca9d6SMichael Rolnik .instance_init = avr_usart_init, 312*429ca9d6SMichael Rolnik .class_init = avr_usart_class_init, 313*429ca9d6SMichael Rolnik }; 314*429ca9d6SMichael Rolnik 315*429ca9d6SMichael Rolnik static void avr_usart_register_types(void) 316*429ca9d6SMichael Rolnik { 317*429ca9d6SMichael Rolnik type_register_static(&avr_usart_info); 318*429ca9d6SMichael Rolnik } 319*429ca9d6SMichael Rolnik 320*429ca9d6SMichael Rolnik type_init(avr_usart_register_types) 321