mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-23 19:49:43 +00:00
milkymist_uart: support new core version
The new version of the uart core introduces status and control bits. Signed-off-by: Michael Walle <michael@walle.cc>
This commit is contained in:
parent
27f930c5f0
commit
fcfa339778
@ -5,15 +5,14 @@
|
||||
#include "qdev-addr.h"
|
||||
|
||||
static inline DeviceState *milkymist_uart_create(target_phys_addr_t base,
|
||||
qemu_irq rx_irq, qemu_irq tx_irq)
|
||||
qemu_irq irq)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
dev = qdev_create(NULL, "milkymist-uart");
|
||||
qdev_init_nofail(dev);
|
||||
sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
|
||||
sysbus_connect_irq(sysbus_from_qdev(dev), 0, rx_irq);
|
||||
sysbus_connect_irq(sysbus_from_qdev(dev), 1, tx_irq);
|
||||
sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
@ -30,19 +30,53 @@
|
||||
enum {
|
||||
R_RXTX = 0,
|
||||
R_DIV,
|
||||
R_STAT,
|
||||
R_CTRL,
|
||||
R_DBG,
|
||||
R_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
STAT_THRE = (1<<0),
|
||||
STAT_RX_EVT = (1<<1),
|
||||
STAT_TX_EVT = (1<<2),
|
||||
};
|
||||
|
||||
enum {
|
||||
CTRL_RX_IRQ_EN = (1<<0),
|
||||
CTRL_TX_IRQ_EN = (1<<1),
|
||||
CTRL_THRU_EN = (1<<2),
|
||||
};
|
||||
|
||||
enum {
|
||||
DBG_BREAK_EN = (1<<0),
|
||||
};
|
||||
|
||||
struct MilkymistUartState {
|
||||
SysBusDevice busdev;
|
||||
CharDriverState *chr;
|
||||
qemu_irq rx_irq;
|
||||
qemu_irq tx_irq;
|
||||
qemu_irq irq;
|
||||
|
||||
uint32_t regs[R_MAX];
|
||||
};
|
||||
typedef struct MilkymistUartState MilkymistUartState;
|
||||
|
||||
static void uart_update_irq(MilkymistUartState *s)
|
||||
{
|
||||
int rx_event = s->regs[R_STAT] & STAT_RX_EVT;
|
||||
int tx_event = s->regs[R_STAT] & STAT_TX_EVT;
|
||||
int rx_irq_en = s->regs[R_CTRL] & CTRL_RX_IRQ_EN;
|
||||
int tx_irq_en = s->regs[R_CTRL] & CTRL_TX_IRQ_EN;
|
||||
|
||||
if ((rx_irq_en && rx_event) || (tx_irq_en && tx_event)) {
|
||||
trace_milkymist_uart_raise_irq();
|
||||
qemu_irq_raise(s->irq);
|
||||
} else {
|
||||
trace_milkymist_uart_lower_irq();
|
||||
qemu_irq_lower(s->irq);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t uart_read(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
MilkymistUartState *s = opaque;
|
||||
@ -51,7 +85,12 @@ static uint32_t uart_read(void *opaque, target_phys_addr_t addr)
|
||||
addr >>= 2;
|
||||
switch (addr) {
|
||||
case R_RXTX:
|
||||
r = s->regs[addr];
|
||||
break;
|
||||
case R_DIV:
|
||||
case R_STAT:
|
||||
case R_CTRL:
|
||||
case R_DBG:
|
||||
r = s->regs[addr];
|
||||
break;
|
||||
|
||||
@ -79,18 +118,26 @@ static void uart_write(void *opaque, target_phys_addr_t addr, uint32_t value)
|
||||
if (s->chr) {
|
||||
qemu_chr_fe_write(s->chr, &ch, 1);
|
||||
}
|
||||
trace_milkymist_uart_pulse_irq_tx();
|
||||
qemu_irq_pulse(s->tx_irq);
|
||||
s->regs[R_STAT] |= STAT_TX_EVT;
|
||||
break;
|
||||
case R_DIV:
|
||||
case R_CTRL:
|
||||
case R_DBG:
|
||||
s->regs[addr] = value;
|
||||
break;
|
||||
|
||||
case R_STAT:
|
||||
/* write one to clear bits */
|
||||
s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT));
|
||||
break;
|
||||
|
||||
default:
|
||||
error_report("milkymist_uart: write access to unknown register 0x"
|
||||
TARGET_FMT_plx, addr << 2);
|
||||
break;
|
||||
}
|
||||
|
||||
uart_update_irq(s);
|
||||
}
|
||||
|
||||
static CPUReadMemoryFunc * const uart_read_fn[] = {
|
||||
@ -109,14 +156,19 @@ static void uart_rx(void *opaque, const uint8_t *buf, int size)
|
||||
{
|
||||
MilkymistUartState *s = opaque;
|
||||
|
||||
assert(!(s->regs[R_STAT] & STAT_RX_EVT));
|
||||
|
||||
s->regs[R_STAT] |= STAT_RX_EVT;
|
||||
s->regs[R_RXTX] = *buf;
|
||||
trace_milkymist_uart_pulse_irq_rx();
|
||||
qemu_irq_pulse(s->rx_irq);
|
||||
|
||||
uart_update_irq(s);
|
||||
}
|
||||
|
||||
static int uart_can_rx(void *opaque)
|
||||
{
|
||||
return 1;
|
||||
MilkymistUartState *s = opaque;
|
||||
|
||||
return !(s->regs[R_STAT] & STAT_RX_EVT);
|
||||
}
|
||||
|
||||
static void uart_event(void *opaque, int event)
|
||||
@ -131,6 +183,9 @@ static void milkymist_uart_reset(DeviceState *d)
|
||||
for (i = 0; i < R_MAX; i++) {
|
||||
s->regs[i] = 0;
|
||||
}
|
||||
|
||||
/* THRE is always set */
|
||||
s->regs[R_STAT] = STAT_THRE;
|
||||
}
|
||||
|
||||
static int milkymist_uart_init(SysBusDevice *dev)
|
||||
@ -138,8 +193,7 @@ static int milkymist_uart_init(SysBusDevice *dev)
|
||||
MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev);
|
||||
int uart_regs;
|
||||
|
||||
sysbus_init_irq(dev, &s->rx_irq);
|
||||
sysbus_init_irq(dev, &s->tx_irq);
|
||||
sysbus_init_irq(dev, &s->irq);
|
||||
|
||||
uart_regs = cpu_register_io_memory(uart_read_fn, uart_write_fn, s,
|
||||
DEVICE_NATIVE_ENDIAN);
|
||||
|
@ -146,7 +146,7 @@ milkymist_init(ram_addr_t ram_size_not_used,
|
||||
exit(1);
|
||||
}
|
||||
|
||||
milkymist_uart_create(0x60000000, irq[0], irq[1]);
|
||||
milkymist_uart_create(0x60000000, irq[0]);
|
||||
milkymist_sysctl_create(0x60001000, irq[2], irq[3], irq[4],
|
||||
80000000, 0x10014d31, 0x0000041f, 0x00000001);
|
||||
milkymist_hpdmc_create(0x60002000);
|
||||
|
@ -444,8 +444,8 @@ milkymist_tmu2_pulse_irq(void) "Pulse IRQ"
|
||||
# hw/milkymist-uart.c
|
||||
milkymist_uart_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
|
||||
milkymist_uart_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
|
||||
milkymist_uart_pulse_irq_rx(void) "Pulse IRQ RX"
|
||||
milkymist_uart_pulse_irq_tx(void) "Pulse IRQ TX"
|
||||
milkymist_uart_raise_irq(void) "Raise IRQ"
|
||||
milkymist_uart_lower_irq(void) "Lower IRQ"
|
||||
|
||||
# hw/milkymist-vgafb.c
|
||||
milkymist_vgafb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
|
||||
|
Loading…
Reference in New Issue
Block a user