xref: /openbmc/qemu/hw/char/shakti_uart.c (revision d2dfe0b5)
1 /*
2  * SHAKTI UART
3  *
4  * Copyright (c) 2021 Vijai Kumar K <vijai@behindbytes.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 
25 #include "qemu/osdep.h"
26 #include "hw/char/shakti_uart.h"
27 #include "hw/qdev-properties.h"
28 #include "hw/qdev-properties-system.h"
29 #include "qemu/log.h"
30 
31 static uint64_t shakti_uart_read(void *opaque, hwaddr addr, unsigned size)
32 {
33     ShaktiUartState *s = opaque;
34 
35     switch (addr) {
36     case SHAKTI_UART_BAUD:
37         return s->uart_baud;
38     case SHAKTI_UART_RX:
39         qemu_chr_fe_accept_input(&s->chr);
40         s->uart_status &= ~SHAKTI_UART_STATUS_RX_NOT_EMPTY;
41         return s->uart_rx;
42     case SHAKTI_UART_STATUS:
43         return s->uart_status;
44     case SHAKTI_UART_DELAY:
45         return s->uart_delay;
46     case SHAKTI_UART_CONTROL:
47         return s->uart_control;
48     case SHAKTI_UART_INT_EN:
49         return s->uart_interrupt;
50     case SHAKTI_UART_IQ_CYCLES:
51         return s->uart_iq_cycles;
52     case SHAKTI_UART_RX_THRES:
53         return s->uart_rx_threshold;
54     default:
55         /* Also handles TX REG which is write only */
56         qemu_log_mask(LOG_GUEST_ERROR,
57                       "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
58     }
59 
60     return 0;
61 }
62 
63 static void shakti_uart_write(void *opaque, hwaddr addr,
64                               uint64_t data, unsigned size)
65 {
66     ShaktiUartState *s = opaque;
67     uint32_t value = data;
68     uint8_t ch;
69 
70     switch (addr) {
71     case SHAKTI_UART_BAUD:
72         s->uart_baud = value;
73         break;
74     case SHAKTI_UART_TX:
75         ch = value;
76         qemu_chr_fe_write_all(&s->chr, &ch, 1);
77         s->uart_status &= ~SHAKTI_UART_STATUS_TX_FULL;
78         break;
79     case SHAKTI_UART_STATUS:
80         s->uart_status = value;
81         break;
82     case SHAKTI_UART_DELAY:
83         s->uart_delay = value;
84         break;
85     case SHAKTI_UART_CONTROL:
86         s->uart_control = value;
87         break;
88     case SHAKTI_UART_INT_EN:
89         s->uart_interrupt = value;
90         break;
91     case SHAKTI_UART_IQ_CYCLES:
92         s->uart_iq_cycles = value;
93         break;
94     case SHAKTI_UART_RX_THRES:
95         s->uart_rx_threshold = value;
96         break;
97     default:
98         qemu_log_mask(LOG_GUEST_ERROR,
99                       "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
100     }
101 }
102 
103 static const MemoryRegionOps shakti_uart_ops = {
104     .read = shakti_uart_read,
105     .write = shakti_uart_write,
106     .endianness = DEVICE_NATIVE_ENDIAN,
107     .impl = {.min_access_size = 1, .max_access_size = 4},
108     .valid = {.min_access_size = 1, .max_access_size = 4},
109 };
110 
111 static void shakti_uart_reset(DeviceState *dev)
112 {
113     ShaktiUartState *s = SHAKTI_UART(dev);
114 
115     s->uart_baud = SHAKTI_UART_BAUD_DEFAULT;
116     s->uart_tx = 0x0;
117     s->uart_rx = 0x0;
118     s->uart_status = 0x0000;
119     s->uart_delay = 0x0000;
120     s->uart_control = SHAKTI_UART_CONTROL_DEFAULT;
121     s->uart_interrupt = 0x0000;
122     s->uart_iq_cycles = 0x00;
123     s->uart_rx_threshold = 0x00;
124 }
125 
126 static int shakti_uart_can_receive(void *opaque)
127 {
128     ShaktiUartState *s = opaque;
129 
130     return !(s->uart_status & SHAKTI_UART_STATUS_RX_NOT_EMPTY);
131 }
132 
133 static void shakti_uart_receive(void *opaque, const uint8_t *buf, int size)
134 {
135     ShaktiUartState *s = opaque;
136 
137     s->uart_rx = *buf;
138     s->uart_status |= SHAKTI_UART_STATUS_RX_NOT_EMPTY;
139 }
140 
141 static void shakti_uart_realize(DeviceState *dev, Error **errp)
142 {
143     ShaktiUartState *sus = SHAKTI_UART(dev);
144     qemu_chr_fe_set_handlers(&sus->chr, shakti_uart_can_receive,
145                              shakti_uart_receive, NULL, NULL, sus, NULL, true);
146 }
147 
148 static void shakti_uart_instance_init(Object *obj)
149 {
150     ShaktiUartState *sus = SHAKTI_UART(obj);
151     memory_region_init_io(&sus->mmio,
152                           obj,
153                           &shakti_uart_ops,
154                           sus,
155                           TYPE_SHAKTI_UART,
156                           0x1000);
157     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &sus->mmio);
158 }
159 
160 static Property shakti_uart_properties[] = {
161     DEFINE_PROP_CHR("chardev", ShaktiUartState, chr),
162     DEFINE_PROP_END_OF_LIST(),
163 };
164 
165 static void shakti_uart_class_init(ObjectClass *klass, void *data)
166 {
167     DeviceClass *dc = DEVICE_CLASS(klass);
168     dc->reset = shakti_uart_reset;
169     dc->realize = shakti_uart_realize;
170     device_class_set_props(dc, shakti_uart_properties);
171     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
172 }
173 
174 static const TypeInfo shakti_uart_info = {
175     .name = TYPE_SHAKTI_UART,
176     .parent = TYPE_SYS_BUS_DEVICE,
177     .instance_size = sizeof(ShaktiUartState),
178     .class_init = shakti_uart_class_init,
179     .instance_init = shakti_uart_instance_init,
180 };
181 
182 static void shakti_uart_register_types(void)
183 {
184     type_register_static(&shakti_uart_info);
185 }
186 type_init(shakti_uart_register_types)
187