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
shakti_uart_read(void * opaque,hwaddr addr,unsigned size)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
shakti_uart_write(void * opaque,hwaddr addr,uint64_t data,unsigned size)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
shakti_uart_reset(DeviceState * dev)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
shakti_uart_can_receive(void * opaque)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
shakti_uart_receive(void * opaque,const uint8_t * buf,int size)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
shakti_uart_realize(DeviceState * dev,Error ** errp)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
shakti_uart_instance_init(Object * obj)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
shakti_uart_class_init(ObjectClass * klass,void * data)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
shakti_uart_register_types(void)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