1b609b7e3SBin Meng /*
2b609b7e3SBin Meng * QEMU model of the UART on the SiFive E300 and U500 series SOCs.
3b609b7e3SBin Meng *
4b609b7e3SBin Meng * Copyright (c) 2016 Stefan O'Rear
5b609b7e3SBin Meng *
6b609b7e3SBin Meng * This program is free software; you can redistribute it and/or modify it
7b609b7e3SBin Meng * under the terms and conditions of the GNU General Public License,
8b609b7e3SBin Meng * version 2 or later, as published by the Free Software Foundation.
9b609b7e3SBin Meng *
10b609b7e3SBin Meng * This program is distributed in the hope it will be useful, but WITHOUT
11b609b7e3SBin Meng * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12b609b7e3SBin Meng * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13b609b7e3SBin Meng * more details.
14b609b7e3SBin Meng *
15b609b7e3SBin Meng * You should have received a copy of the GNU General Public License along with
16b609b7e3SBin Meng * this program. If not, see <http://www.gnu.org/licenses/>.
17b609b7e3SBin Meng */
18b609b7e3SBin Meng
19b609b7e3SBin Meng #include "qemu/osdep.h"
20b609b7e3SBin Meng #include "qapi/error.h"
21b609b7e3SBin Meng #include "qemu/log.h"
226ee7ba1bSLukas Jünger #include "migration/vmstate.h"
23b609b7e3SBin Meng #include "chardev/char.h"
24b609b7e3SBin Meng #include "chardev/char-fe.h"
25b609b7e3SBin Meng #include "hw/irq.h"
26b609b7e3SBin Meng #include "hw/char/sifive_uart.h"
276ee7ba1bSLukas Jünger #include "hw/qdev-properties-system.h"
28b609b7e3SBin Meng
2953c1557bSAlistair Francis #define TX_INTERRUPT_TRIGGER_DELAY_NS 100
3053c1557bSAlistair Francis
31b609b7e3SBin Meng /*
32b609b7e3SBin Meng * Not yet implemented:
33b609b7e3SBin Meng *
34b609b7e3SBin Meng * Transmit FIFO using "qemu/fifo8.h"
35b609b7e3SBin Meng */
36b609b7e3SBin Meng
37b609b7e3SBin Meng /* Returns the state of the IP (interrupt pending) register */
sifive_uart_ip(SiFiveUARTState * s)38244a9fcbSLukas Jünger static uint64_t sifive_uart_ip(SiFiveUARTState *s)
39b609b7e3SBin Meng {
40b609b7e3SBin Meng uint64_t ret = 0;
41b609b7e3SBin Meng
42b609b7e3SBin Meng uint64_t txcnt = SIFIVE_UART_GET_TXCNT(s->txctrl);
43b609b7e3SBin Meng uint64_t rxcnt = SIFIVE_UART_GET_RXCNT(s->rxctrl);
44b609b7e3SBin Meng
45b609b7e3SBin Meng if (txcnt != 0) {
46b609b7e3SBin Meng ret |= SIFIVE_UART_IP_TXWM;
47b609b7e3SBin Meng }
48b609b7e3SBin Meng if (s->rx_fifo_len > rxcnt) {
49b609b7e3SBin Meng ret |= SIFIVE_UART_IP_RXWM;
50b609b7e3SBin Meng }
51b609b7e3SBin Meng
52b609b7e3SBin Meng return ret;
53b609b7e3SBin Meng }
54b609b7e3SBin Meng
sifive_uart_update_irq(SiFiveUARTState * s)55244a9fcbSLukas Jünger static void sifive_uart_update_irq(SiFiveUARTState *s)
56b609b7e3SBin Meng {
57b609b7e3SBin Meng int cond = 0;
58b609b7e3SBin Meng if ((s->ie & SIFIVE_UART_IE_TXWM) ||
59b609b7e3SBin Meng ((s->ie & SIFIVE_UART_IE_RXWM) && s->rx_fifo_len)) {
60b609b7e3SBin Meng cond = 1;
61b609b7e3SBin Meng }
62b609b7e3SBin Meng if (cond) {
63b609b7e3SBin Meng qemu_irq_raise(s->irq);
64b609b7e3SBin Meng } else {
65b609b7e3SBin Meng qemu_irq_lower(s->irq);
66b609b7e3SBin Meng }
67b609b7e3SBin Meng }
68b609b7e3SBin Meng
sifive_uart_xmit(void * do_not_use,GIOCondition cond,void * opaque)6953c1557bSAlistair Francis static gboolean sifive_uart_xmit(void *do_not_use, GIOCondition cond,
7053c1557bSAlistair Francis void *opaque)
7153c1557bSAlistair Francis {
7253c1557bSAlistair Francis SiFiveUARTState *s = opaque;
7353c1557bSAlistair Francis int ret;
7453c1557bSAlistair Francis const uint8_t *characters;
7553c1557bSAlistair Francis uint32_t numptr = 0;
7653c1557bSAlistair Francis
7753c1557bSAlistair Francis /* instant drain the fifo when there's no back-end */
7853c1557bSAlistair Francis if (!qemu_chr_fe_backend_connected(&s->chr)) {
7953c1557bSAlistair Francis fifo8_reset(&s->tx_fifo);
8053c1557bSAlistair Francis return G_SOURCE_REMOVE;
8153c1557bSAlistair Francis }
8253c1557bSAlistair Francis
8353c1557bSAlistair Francis if (fifo8_is_empty(&s->tx_fifo)) {
8453c1557bSAlistair Francis return G_SOURCE_REMOVE;
8553c1557bSAlistair Francis }
8653c1557bSAlistair Francis
8753c1557bSAlistair Francis /* Don't pop the FIFO in case the write fails */
8853c1557bSAlistair Francis characters = fifo8_peek_bufptr(&s->tx_fifo,
8953c1557bSAlistair Francis fifo8_num_used(&s->tx_fifo), &numptr);
9053c1557bSAlistair Francis ret = qemu_chr_fe_write(&s->chr, characters, numptr);
9153c1557bSAlistair Francis
9253c1557bSAlistair Francis if (ret >= 0) {
9353c1557bSAlistair Francis /* We wrote the data, actually pop the fifo */
9453c1557bSAlistair Francis fifo8_pop_bufptr(&s->tx_fifo, ret, NULL);
9553c1557bSAlistair Francis }
9653c1557bSAlistair Francis
9753c1557bSAlistair Francis if (!fifo8_is_empty(&s->tx_fifo)) {
9853c1557bSAlistair Francis guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
9953c1557bSAlistair Francis sifive_uart_xmit, s);
10053c1557bSAlistair Francis if (!r) {
10153c1557bSAlistair Francis fifo8_reset(&s->tx_fifo);
10253c1557bSAlistair Francis return G_SOURCE_REMOVE;
10353c1557bSAlistair Francis }
10453c1557bSAlistair Francis }
10553c1557bSAlistair Francis
10653c1557bSAlistair Francis /* Clear the TX Full bit */
10753c1557bSAlistair Francis if (!fifo8_is_full(&s->tx_fifo)) {
10853c1557bSAlistair Francis s->txfifo &= ~SIFIVE_UART_TXFIFO_FULL;
10953c1557bSAlistair Francis }
11053c1557bSAlistair Francis
11153c1557bSAlistair Francis sifive_uart_update_irq(s);
11253c1557bSAlistair Francis return G_SOURCE_REMOVE;
11353c1557bSAlistair Francis }
11453c1557bSAlistair Francis
sifive_uart_write_tx_fifo(SiFiveUARTState * s,const uint8_t * buf,int size)11553c1557bSAlistair Francis static void sifive_uart_write_tx_fifo(SiFiveUARTState *s, const uint8_t *buf,
11653c1557bSAlistair Francis int size)
11753c1557bSAlistair Francis {
11853c1557bSAlistair Francis uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
11953c1557bSAlistair Francis
12053c1557bSAlistair Francis if (size > fifo8_num_free(&s->tx_fifo)) {
12153c1557bSAlistair Francis size = fifo8_num_free(&s->tx_fifo);
12253c1557bSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, "sifive_uart: TX FIFO overflow");
12353c1557bSAlistair Francis }
12453c1557bSAlistair Francis
12553c1557bSAlistair Francis fifo8_push_all(&s->tx_fifo, buf, size);
12653c1557bSAlistair Francis
12753c1557bSAlistair Francis if (fifo8_is_full(&s->tx_fifo)) {
12853c1557bSAlistair Francis s->txfifo |= SIFIVE_UART_TXFIFO_FULL;
12953c1557bSAlistair Francis }
13053c1557bSAlistair Francis
13153c1557bSAlistair Francis timer_mod(s->fifo_trigger_handle, current_time +
13253c1557bSAlistair Francis TX_INTERRUPT_TRIGGER_DELAY_NS);
13353c1557bSAlistair Francis }
13453c1557bSAlistair Francis
135b609b7e3SBin Meng static uint64_t
sifive_uart_read(void * opaque,hwaddr addr,unsigned int size)136244a9fcbSLukas Jünger sifive_uart_read(void *opaque, hwaddr addr, unsigned int size)
137b609b7e3SBin Meng {
138b609b7e3SBin Meng SiFiveUARTState *s = opaque;
139b609b7e3SBin Meng unsigned char r;
140b609b7e3SBin Meng switch (addr) {
141b609b7e3SBin Meng case SIFIVE_UART_RXFIFO:
142b609b7e3SBin Meng if (s->rx_fifo_len) {
143b609b7e3SBin Meng r = s->rx_fifo[0];
144b609b7e3SBin Meng memmove(s->rx_fifo, s->rx_fifo + 1, s->rx_fifo_len - 1);
145b609b7e3SBin Meng s->rx_fifo_len--;
146b609b7e3SBin Meng qemu_chr_fe_accept_input(&s->chr);
147244a9fcbSLukas Jünger sifive_uart_update_irq(s);
148b609b7e3SBin Meng return r;
149b609b7e3SBin Meng }
150b609b7e3SBin Meng return 0x80000000;
151b609b7e3SBin Meng
152b609b7e3SBin Meng case SIFIVE_UART_TXFIFO:
15353c1557bSAlistair Francis return s->txfifo;
154b609b7e3SBin Meng case SIFIVE_UART_IE:
155b609b7e3SBin Meng return s->ie;
156b609b7e3SBin Meng case SIFIVE_UART_IP:
157244a9fcbSLukas Jünger return sifive_uart_ip(s);
158b609b7e3SBin Meng case SIFIVE_UART_TXCTRL:
159b609b7e3SBin Meng return s->txctrl;
160b609b7e3SBin Meng case SIFIVE_UART_RXCTRL:
161b609b7e3SBin Meng return s->rxctrl;
162b609b7e3SBin Meng case SIFIVE_UART_DIV:
163b609b7e3SBin Meng return s->div;
164b609b7e3SBin Meng }
165b609b7e3SBin Meng
166b609b7e3SBin Meng qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read: addr=0x%x\n",
167b609b7e3SBin Meng __func__, (int)addr);
168b609b7e3SBin Meng return 0;
169b609b7e3SBin Meng }
170b609b7e3SBin Meng
171b609b7e3SBin Meng static void
sifive_uart_write(void * opaque,hwaddr addr,uint64_t val64,unsigned int size)172244a9fcbSLukas Jünger sifive_uart_write(void *opaque, hwaddr addr,
173b609b7e3SBin Meng uint64_t val64, unsigned int size)
174b609b7e3SBin Meng {
175b609b7e3SBin Meng SiFiveUARTState *s = opaque;
176b609b7e3SBin Meng uint32_t value = val64;
177*b069018eSThomas Huth uint8_t ch = value;
178b609b7e3SBin Meng
179b609b7e3SBin Meng switch (addr) {
180b609b7e3SBin Meng case SIFIVE_UART_TXFIFO:
181*b069018eSThomas Huth sifive_uart_write_tx_fifo(s, &ch, 1);
182b609b7e3SBin Meng return;
183b609b7e3SBin Meng case SIFIVE_UART_IE:
184b609b7e3SBin Meng s->ie = val64;
185244a9fcbSLukas Jünger sifive_uart_update_irq(s);
186b609b7e3SBin Meng return;
187b609b7e3SBin Meng case SIFIVE_UART_TXCTRL:
188b609b7e3SBin Meng s->txctrl = val64;
189b609b7e3SBin Meng return;
190b609b7e3SBin Meng case SIFIVE_UART_RXCTRL:
191b609b7e3SBin Meng s->rxctrl = val64;
192b609b7e3SBin Meng return;
193b609b7e3SBin Meng case SIFIVE_UART_DIV:
194b609b7e3SBin Meng s->div = val64;
195b609b7e3SBin Meng return;
196b609b7e3SBin Meng }
197b609b7e3SBin Meng qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%x v=0x%x\n",
198b609b7e3SBin Meng __func__, (int)addr, (int)value);
199b609b7e3SBin Meng }
200b609b7e3SBin Meng
fifo_trigger_update(void * opaque)20153c1557bSAlistair Francis static void fifo_trigger_update(void *opaque)
20253c1557bSAlistair Francis {
20353c1557bSAlistair Francis SiFiveUARTState *s = opaque;
20453c1557bSAlistair Francis
20553c1557bSAlistair Francis sifive_uart_xmit(NULL, G_IO_OUT, s);
20653c1557bSAlistair Francis }
20753c1557bSAlistair Francis
208244a9fcbSLukas Jünger static const MemoryRegionOps sifive_uart_ops = {
209244a9fcbSLukas Jünger .read = sifive_uart_read,
210244a9fcbSLukas Jünger .write = sifive_uart_write,
211b609b7e3SBin Meng .endianness = DEVICE_NATIVE_ENDIAN,
212b609b7e3SBin Meng .valid = {
213b609b7e3SBin Meng .min_access_size = 4,
214b609b7e3SBin Meng .max_access_size = 4
215b609b7e3SBin Meng }
216b609b7e3SBin Meng };
217b609b7e3SBin Meng
sifive_uart_rx(void * opaque,const uint8_t * buf,int size)218244a9fcbSLukas Jünger static void sifive_uart_rx(void *opaque, const uint8_t *buf, int size)
219b609b7e3SBin Meng {
220b609b7e3SBin Meng SiFiveUARTState *s = opaque;
221b609b7e3SBin Meng
222b609b7e3SBin Meng /* Got a byte. */
223b609b7e3SBin Meng if (s->rx_fifo_len >= sizeof(s->rx_fifo)) {
224b609b7e3SBin Meng printf("WARNING: UART dropped char.\n");
225b609b7e3SBin Meng return;
226b609b7e3SBin Meng }
227b609b7e3SBin Meng s->rx_fifo[s->rx_fifo_len++] = *buf;
228b609b7e3SBin Meng
229244a9fcbSLukas Jünger sifive_uart_update_irq(s);
230b609b7e3SBin Meng }
231b609b7e3SBin Meng
sifive_uart_can_rx(void * opaque)232244a9fcbSLukas Jünger static int sifive_uart_can_rx(void *opaque)
233b609b7e3SBin Meng {
234b609b7e3SBin Meng SiFiveUARTState *s = opaque;
235b609b7e3SBin Meng
236b609b7e3SBin Meng return s->rx_fifo_len < sizeof(s->rx_fifo);
237b609b7e3SBin Meng }
238b609b7e3SBin Meng
sifive_uart_event(void * opaque,QEMUChrEvent event)239244a9fcbSLukas Jünger static void sifive_uart_event(void *opaque, QEMUChrEvent event)
240b609b7e3SBin Meng {
241b609b7e3SBin Meng }
242b609b7e3SBin Meng
sifive_uart_be_change(void * opaque)243244a9fcbSLukas Jünger static int sifive_uart_be_change(void *opaque)
244b609b7e3SBin Meng {
245b609b7e3SBin Meng SiFiveUARTState *s = opaque;
246b609b7e3SBin Meng
247244a9fcbSLukas Jünger qemu_chr_fe_set_handlers(&s->chr, sifive_uart_can_rx, sifive_uart_rx,
248244a9fcbSLukas Jünger sifive_uart_event, sifive_uart_be_change, s,
249244a9fcbSLukas Jünger NULL, true);
250b609b7e3SBin Meng
251b609b7e3SBin Meng return 0;
252b609b7e3SBin Meng }
253b609b7e3SBin Meng
2546ee7ba1bSLukas Jünger static Property sifive_uart_properties[] = {
2556ee7ba1bSLukas Jünger DEFINE_PROP_CHR("chardev", SiFiveUARTState, chr),
2566ee7ba1bSLukas Jünger DEFINE_PROP_END_OF_LIST(),
2576ee7ba1bSLukas Jünger };
2586ee7ba1bSLukas Jünger
sifive_uart_init(Object * obj)2596ee7ba1bSLukas Jünger static void sifive_uart_init(Object *obj)
2606ee7ba1bSLukas Jünger {
2616ee7ba1bSLukas Jünger SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
2626ee7ba1bSLukas Jünger SiFiveUARTState *s = SIFIVE_UART(obj);
2636ee7ba1bSLukas Jünger
2646ee7ba1bSLukas Jünger memory_region_init_io(&s->mmio, OBJECT(s), &sifive_uart_ops, s,
2656ee7ba1bSLukas Jünger TYPE_SIFIVE_UART, SIFIVE_UART_MAX);
2666ee7ba1bSLukas Jünger sysbus_init_mmio(sbd, &s->mmio);
2676ee7ba1bSLukas Jünger sysbus_init_irq(sbd, &s->irq);
2686ee7ba1bSLukas Jünger }
2696ee7ba1bSLukas Jünger
sifive_uart_realize(DeviceState * dev,Error ** errp)2706ee7ba1bSLukas Jünger static void sifive_uart_realize(DeviceState *dev, Error **errp)
2716ee7ba1bSLukas Jünger {
2726ee7ba1bSLukas Jünger SiFiveUARTState *s = SIFIVE_UART(dev);
2736ee7ba1bSLukas Jünger
27453c1557bSAlistair Francis s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
27553c1557bSAlistair Francis fifo_trigger_update, s);
27653c1557bSAlistair Francis
2776ee7ba1bSLukas Jünger qemu_chr_fe_set_handlers(&s->chr, sifive_uart_can_rx, sifive_uart_rx,
2786ee7ba1bSLukas Jünger sifive_uart_event, sifive_uart_be_change, s,
2796ee7ba1bSLukas Jünger NULL, true);
2806ee7ba1bSLukas Jünger
2816ee7ba1bSLukas Jünger }
2826ee7ba1bSLukas Jünger
sifive_uart_reset_enter(Object * obj,ResetType type)2836ee7ba1bSLukas Jünger static void sifive_uart_reset_enter(Object *obj, ResetType type)
2846ee7ba1bSLukas Jünger {
2856ee7ba1bSLukas Jünger SiFiveUARTState *s = SIFIVE_UART(obj);
28653c1557bSAlistair Francis
28753c1557bSAlistair Francis s->txfifo = 0;
2886ee7ba1bSLukas Jünger s->ie = 0;
2896ee7ba1bSLukas Jünger s->ip = 0;
2906ee7ba1bSLukas Jünger s->txctrl = 0;
2916ee7ba1bSLukas Jünger s->rxctrl = 0;
2926ee7ba1bSLukas Jünger s->div = 0;
29353c1557bSAlistair Francis
2946ee7ba1bSLukas Jünger s->rx_fifo_len = 0;
29553c1557bSAlistair Francis
29653c1557bSAlistair Francis memset(s->rx_fifo, 0, SIFIVE_UART_RX_FIFO_SIZE);
29753c1557bSAlistair Francis fifo8_create(&s->tx_fifo, SIFIVE_UART_TX_FIFO_SIZE);
2986ee7ba1bSLukas Jünger }
2996ee7ba1bSLukas Jünger
sifive_uart_reset_hold(Object * obj,ResetType type)300ad80e367SPeter Maydell static void sifive_uart_reset_hold(Object *obj, ResetType type)
3016ee7ba1bSLukas Jünger {
3026ee7ba1bSLukas Jünger SiFiveUARTState *s = SIFIVE_UART(obj);
3036ee7ba1bSLukas Jünger qemu_irq_lower(s->irq);
3046ee7ba1bSLukas Jünger }
3056ee7ba1bSLukas Jünger
3066ee7ba1bSLukas Jünger static const VMStateDescription vmstate_sifive_uart = {
3076ee7ba1bSLukas Jünger .name = TYPE_SIFIVE_UART,
30853c1557bSAlistair Francis .version_id = 2,
30953c1557bSAlistair Francis .minimum_version_id = 2,
3102f6cab05SRichard Henderson .fields = (const VMStateField[]) {
3116ee7ba1bSLukas Jünger VMSTATE_UINT8_ARRAY(rx_fifo, SiFiveUARTState,
3126ee7ba1bSLukas Jünger SIFIVE_UART_RX_FIFO_SIZE),
3136ee7ba1bSLukas Jünger VMSTATE_UINT8(rx_fifo_len, SiFiveUARTState),
3146ee7ba1bSLukas Jünger VMSTATE_UINT32(ie, SiFiveUARTState),
3156ee7ba1bSLukas Jünger VMSTATE_UINT32(ip, SiFiveUARTState),
3166ee7ba1bSLukas Jünger VMSTATE_UINT32(txctrl, SiFiveUARTState),
3176ee7ba1bSLukas Jünger VMSTATE_UINT32(rxctrl, SiFiveUARTState),
3186ee7ba1bSLukas Jünger VMSTATE_UINT32(div, SiFiveUARTState),
31953c1557bSAlistair Francis VMSTATE_UINT32(txfifo, SiFiveUARTState),
32053c1557bSAlistair Francis VMSTATE_FIFO8(tx_fifo, SiFiveUARTState),
32153c1557bSAlistair Francis VMSTATE_TIMER_PTR(fifo_trigger_handle, SiFiveUARTState),
3226ee7ba1bSLukas Jünger VMSTATE_END_OF_LIST()
3236ee7ba1bSLukas Jünger },
3246ee7ba1bSLukas Jünger };
3256ee7ba1bSLukas Jünger
3266ee7ba1bSLukas Jünger
sifive_uart_class_init(ObjectClass * oc,void * data)3276ee7ba1bSLukas Jünger static void sifive_uart_class_init(ObjectClass *oc, void *data)
3286ee7ba1bSLukas Jünger {
3296ee7ba1bSLukas Jünger DeviceClass *dc = DEVICE_CLASS(oc);
3306ee7ba1bSLukas Jünger ResettableClass *rc = RESETTABLE_CLASS(oc);
3316ee7ba1bSLukas Jünger
3326ee7ba1bSLukas Jünger dc->realize = sifive_uart_realize;
3336ee7ba1bSLukas Jünger dc->vmsd = &vmstate_sifive_uart;
3346ee7ba1bSLukas Jünger rc->phases.enter = sifive_uart_reset_enter;
3356ee7ba1bSLukas Jünger rc->phases.hold = sifive_uart_reset_hold;
3366ee7ba1bSLukas Jünger device_class_set_props(dc, sifive_uart_properties);
3376a033490SBin Meng set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
3386ee7ba1bSLukas Jünger }
3396ee7ba1bSLukas Jünger
3406ee7ba1bSLukas Jünger static const TypeInfo sifive_uart_info = {
3416ee7ba1bSLukas Jünger .name = TYPE_SIFIVE_UART,
3426ee7ba1bSLukas Jünger .parent = TYPE_SYS_BUS_DEVICE,
3436ee7ba1bSLukas Jünger .instance_size = sizeof(SiFiveUARTState),
3446ee7ba1bSLukas Jünger .instance_init = sifive_uart_init,
3456ee7ba1bSLukas Jünger .class_init = sifive_uart_class_init,
3466ee7ba1bSLukas Jünger };
3476ee7ba1bSLukas Jünger
sifive_uart_register_types(void)3486ee7ba1bSLukas Jünger static void sifive_uart_register_types(void)
3496ee7ba1bSLukas Jünger {
3506ee7ba1bSLukas Jünger type_register_static(&sifive_uart_info);
3516ee7ba1bSLukas Jünger }
3526ee7ba1bSLukas Jünger
type_init(sifive_uart_register_types)3536ee7ba1bSLukas Jünger type_init(sifive_uart_register_types)
3546ee7ba1bSLukas Jünger
355b609b7e3SBin Meng /*
356b609b7e3SBin Meng * Create UART device.
357b609b7e3SBin Meng */
358b609b7e3SBin Meng SiFiveUARTState *sifive_uart_create(MemoryRegion *address_space, hwaddr base,
359b609b7e3SBin Meng Chardev *chr, qemu_irq irq)
360b609b7e3SBin Meng {
3616ee7ba1bSLukas Jünger DeviceState *dev;
3626ee7ba1bSLukas Jünger SysBusDevice *s;
3636ee7ba1bSLukas Jünger
3646ee7ba1bSLukas Jünger dev = qdev_new("riscv.sifive.uart");
3656ee7ba1bSLukas Jünger s = SYS_BUS_DEVICE(dev);
3666ee7ba1bSLukas Jünger qdev_prop_set_chr(dev, "chardev", chr);
3676ee7ba1bSLukas Jünger sysbus_realize_and_unref(s, &error_fatal);
3686ee7ba1bSLukas Jünger memory_region_add_subregion(address_space, base,
3696ee7ba1bSLukas Jünger sysbus_mmio_get_region(s, 0));
3706ee7ba1bSLukas Jünger sysbus_connect_irq(s, 0, irq);
3716ee7ba1bSLukas Jünger
37266997c42SMarkus Armbruster return SIFIVE_UART(dev);
373b609b7e3SBin Meng }
374