107f334d8SVijai Kumar K /* 207f334d8SVijai Kumar K * SHAKTI UART 307f334d8SVijai Kumar K * 407f334d8SVijai Kumar K * Copyright (c) 2021 Vijai Kumar K <vijai@behindbytes.com> 507f334d8SVijai Kumar K * 607f334d8SVijai Kumar K * Permission is hereby granted, free of charge, to any person obtaining a copy 707f334d8SVijai Kumar K * of this software and associated documentation files (the "Software"), to deal 807f334d8SVijai Kumar K * in the Software without restriction, including without limitation the rights 907f334d8SVijai Kumar K * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1007f334d8SVijai Kumar K * copies of the Software, and to permit persons to whom the Software is 1107f334d8SVijai Kumar K * furnished to do so, subject to the following conditions: 1207f334d8SVijai Kumar K * 1307f334d8SVijai Kumar K * The above copyright notice and this permission notice shall be included in 1407f334d8SVijai Kumar K * all copies or substantial portions of the Software. 1507f334d8SVijai Kumar K * 1607f334d8SVijai Kumar K * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1707f334d8SVijai Kumar K * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1807f334d8SVijai Kumar K * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1907f334d8SVijai Kumar K * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2007f334d8SVijai Kumar K * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2107f334d8SVijai Kumar K * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2207f334d8SVijai Kumar K * THE SOFTWARE. 2307f334d8SVijai Kumar K */ 2407f334d8SVijai Kumar K 2507f334d8SVijai Kumar K #include "qemu/osdep.h" 2607f334d8SVijai Kumar K #include "hw/char/shakti_uart.h" 2707f334d8SVijai Kumar K #include "hw/qdev-properties.h" 2807f334d8SVijai Kumar K #include "hw/qdev-properties-system.h" 2907f334d8SVijai Kumar K #include "qemu/log.h" 3007f334d8SVijai Kumar K 3107f334d8SVijai Kumar K static uint64_t shakti_uart_read(void *opaque, hwaddr addr, unsigned size) 3207f334d8SVijai Kumar K { 3307f334d8SVijai Kumar K ShaktiUartState *s = opaque; 3407f334d8SVijai Kumar K 3507f334d8SVijai Kumar K switch (addr) { 3607f334d8SVijai Kumar K case SHAKTI_UART_BAUD: 3707f334d8SVijai Kumar K return s->uart_baud; 3807f334d8SVijai Kumar K case SHAKTI_UART_RX: 3907f334d8SVijai Kumar K qemu_chr_fe_accept_input(&s->chr); 4007f334d8SVijai Kumar K s->uart_status &= ~SHAKTI_UART_STATUS_RX_NOT_EMPTY; 4107f334d8SVijai Kumar K return s->uart_rx; 4207f334d8SVijai Kumar K case SHAKTI_UART_STATUS: 4307f334d8SVijai Kumar K return s->uart_status; 4407f334d8SVijai Kumar K case SHAKTI_UART_DELAY: 4507f334d8SVijai Kumar K return s->uart_delay; 4607f334d8SVijai Kumar K case SHAKTI_UART_CONTROL: 4707f334d8SVijai Kumar K return s->uart_control; 4807f334d8SVijai Kumar K case SHAKTI_UART_INT_EN: 4907f334d8SVijai Kumar K return s->uart_interrupt; 5007f334d8SVijai Kumar K case SHAKTI_UART_IQ_CYCLES: 5107f334d8SVijai Kumar K return s->uart_iq_cycles; 5207f334d8SVijai Kumar K case SHAKTI_UART_RX_THRES: 5307f334d8SVijai Kumar K return s->uart_rx_threshold; 5407f334d8SVijai Kumar K default: 5507f334d8SVijai Kumar K /* Also handles TX REG which is write only */ 5607f334d8SVijai Kumar K qemu_log_mask(LOG_GUEST_ERROR, 5707f334d8SVijai Kumar K "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); 5807f334d8SVijai Kumar K } 5907f334d8SVijai Kumar K 6007f334d8SVijai Kumar K return 0; 6107f334d8SVijai Kumar K } 6207f334d8SVijai Kumar K 6307f334d8SVijai Kumar K static void shakti_uart_write(void *opaque, hwaddr addr, 6407f334d8SVijai Kumar K uint64_t data, unsigned size) 6507f334d8SVijai Kumar K { 6607f334d8SVijai Kumar K ShaktiUartState *s = opaque; 6707f334d8SVijai Kumar K uint32_t value = data; 6807f334d8SVijai Kumar K uint8_t ch; 6907f334d8SVijai Kumar K 7007f334d8SVijai Kumar K switch (addr) { 7107f334d8SVijai Kumar K case SHAKTI_UART_BAUD: 7207f334d8SVijai Kumar K s->uart_baud = value; 7307f334d8SVijai Kumar K break; 7407f334d8SVijai Kumar K case SHAKTI_UART_TX: 7507f334d8SVijai Kumar K ch = value; 7607f334d8SVijai Kumar K qemu_chr_fe_write_all(&s->chr, &ch, 1); 7707f334d8SVijai Kumar K s->uart_status &= ~SHAKTI_UART_STATUS_TX_FULL; 7807f334d8SVijai Kumar K break; 7907f334d8SVijai Kumar K case SHAKTI_UART_STATUS: 8007f334d8SVijai Kumar K s->uart_status = value; 8107f334d8SVijai Kumar K break; 8207f334d8SVijai Kumar K case SHAKTI_UART_DELAY: 8307f334d8SVijai Kumar K s->uart_delay = value; 8407f334d8SVijai Kumar K break; 8507f334d8SVijai Kumar K case SHAKTI_UART_CONTROL: 8607f334d8SVijai Kumar K s->uart_control = value; 8707f334d8SVijai Kumar K break; 8807f334d8SVijai Kumar K case SHAKTI_UART_INT_EN: 8907f334d8SVijai Kumar K s->uart_interrupt = value; 9007f334d8SVijai Kumar K break; 9107f334d8SVijai Kumar K case SHAKTI_UART_IQ_CYCLES: 9207f334d8SVijai Kumar K s->uart_iq_cycles = value; 9307f334d8SVijai Kumar K break; 9407f334d8SVijai Kumar K case SHAKTI_UART_RX_THRES: 9507f334d8SVijai Kumar K s->uart_rx_threshold = value; 9607f334d8SVijai Kumar K break; 9707f334d8SVijai Kumar K default: 9807f334d8SVijai Kumar K qemu_log_mask(LOG_GUEST_ERROR, 9907f334d8SVijai Kumar K "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); 10007f334d8SVijai Kumar K } 10107f334d8SVijai Kumar K } 10207f334d8SVijai Kumar K 10307f334d8SVijai Kumar K static const MemoryRegionOps shakti_uart_ops = { 10407f334d8SVijai Kumar K .read = shakti_uart_read, 10507f334d8SVijai Kumar K .write = shakti_uart_write, 10607f334d8SVijai Kumar K .endianness = DEVICE_NATIVE_ENDIAN, 10707f334d8SVijai Kumar K .impl = {.min_access_size = 1, .max_access_size = 4}, 10807f334d8SVijai Kumar K .valid = {.min_access_size = 1, .max_access_size = 4}, 10907f334d8SVijai Kumar K }; 11007f334d8SVijai Kumar K 11107f334d8SVijai Kumar K static void shakti_uart_reset(DeviceState *dev) 11207f334d8SVijai Kumar K { 11307f334d8SVijai Kumar K ShaktiUartState *s = SHAKTI_UART(dev); 11407f334d8SVijai Kumar K 11507f334d8SVijai Kumar K s->uart_baud = SHAKTI_UART_BAUD_DEFAULT; 11607f334d8SVijai Kumar K s->uart_tx = 0x0; 11707f334d8SVijai Kumar K s->uart_rx = 0x0; 11807f334d8SVijai Kumar K s->uart_status = 0x0000; 11907f334d8SVijai Kumar K s->uart_delay = 0x0000; 12007f334d8SVijai Kumar K s->uart_control = SHAKTI_UART_CONTROL_DEFAULT; 12107f334d8SVijai Kumar K s->uart_interrupt = 0x0000; 12207f334d8SVijai Kumar K s->uart_iq_cycles = 0x00; 12307f334d8SVijai Kumar K s->uart_rx_threshold = 0x00; 12407f334d8SVijai Kumar K } 12507f334d8SVijai Kumar K 12607f334d8SVijai Kumar K static int shakti_uart_can_receive(void *opaque) 12707f334d8SVijai Kumar K { 12807f334d8SVijai Kumar K ShaktiUartState *s = opaque; 12907f334d8SVijai Kumar K 13007f334d8SVijai Kumar K return !(s->uart_status & SHAKTI_UART_STATUS_RX_NOT_EMPTY); 13107f334d8SVijai Kumar K } 13207f334d8SVijai Kumar K 13307f334d8SVijai Kumar K static void shakti_uart_receive(void *opaque, const uint8_t *buf, int size) 13407f334d8SVijai Kumar K { 13507f334d8SVijai Kumar K ShaktiUartState *s = opaque; 13607f334d8SVijai Kumar K 13707f334d8SVijai Kumar K s->uart_rx = *buf; 13807f334d8SVijai Kumar K s->uart_status |= SHAKTI_UART_STATUS_RX_NOT_EMPTY; 13907f334d8SVijai Kumar K } 14007f334d8SVijai Kumar K 14107f334d8SVijai Kumar K static void shakti_uart_realize(DeviceState *dev, Error **errp) 14207f334d8SVijai Kumar K { 14307f334d8SVijai Kumar K ShaktiUartState *sus = SHAKTI_UART(dev); 14407f334d8SVijai Kumar K qemu_chr_fe_set_handlers(&sus->chr, shakti_uart_can_receive, 14507f334d8SVijai Kumar K shakti_uart_receive, NULL, NULL, sus, NULL, true); 14607f334d8SVijai Kumar K } 14707f334d8SVijai Kumar K 14807f334d8SVijai Kumar K static void shakti_uart_instance_init(Object *obj) 14907f334d8SVijai Kumar K { 15007f334d8SVijai Kumar K ShaktiUartState *sus = SHAKTI_UART(obj); 15107f334d8SVijai Kumar K memory_region_init_io(&sus->mmio, 15207f334d8SVijai Kumar K obj, 15307f334d8SVijai Kumar K &shakti_uart_ops, 15407f334d8SVijai Kumar K sus, 15507f334d8SVijai Kumar K TYPE_SHAKTI_UART, 15607f334d8SVijai Kumar K 0x1000); 15707f334d8SVijai Kumar K sysbus_init_mmio(SYS_BUS_DEVICE(obj), &sus->mmio); 15807f334d8SVijai Kumar K } 15907f334d8SVijai Kumar K 16007f334d8SVijai Kumar K static Property shakti_uart_properties[] = { 16107f334d8SVijai Kumar K DEFINE_PROP_CHR("chardev", ShaktiUartState, chr), 16207f334d8SVijai Kumar K DEFINE_PROP_END_OF_LIST(), 16307f334d8SVijai Kumar K }; 16407f334d8SVijai Kumar K 16507f334d8SVijai Kumar K static void shakti_uart_class_init(ObjectClass *klass, void *data) 16607f334d8SVijai Kumar K { 16707f334d8SVijai Kumar K DeviceClass *dc = DEVICE_CLASS(klass); 168*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, shakti_uart_reset); 16907f334d8SVijai Kumar K dc->realize = shakti_uart_realize; 17007f334d8SVijai Kumar K device_class_set_props(dc, shakti_uart_properties); 1715515ff16SBin Meng set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 17207f334d8SVijai Kumar K } 17307f334d8SVijai Kumar K 17407f334d8SVijai Kumar K static const TypeInfo shakti_uart_info = { 17507f334d8SVijai Kumar K .name = TYPE_SHAKTI_UART, 17607f334d8SVijai Kumar K .parent = TYPE_SYS_BUS_DEVICE, 17707f334d8SVijai Kumar K .instance_size = sizeof(ShaktiUartState), 17807f334d8SVijai Kumar K .class_init = shakti_uart_class_init, 17907f334d8SVijai Kumar K .instance_init = shakti_uart_instance_init, 18007f334d8SVijai Kumar K }; 18107f334d8SVijai Kumar K 18207f334d8SVijai Kumar K static void shakti_uart_register_types(void) 18307f334d8SVijai Kumar K { 18407f334d8SVijai Kumar K type_register_static(&shakti_uart_info); 18507f334d8SVijai Kumar K } 18607f334d8SVijai Kumar K type_init(shakti_uart_register_types) 187