mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-27 13:30:52 +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"
|
#include "qdev-addr.h"
|
||||||
|
|
||||||
static inline DeviceState *milkymist_uart_create(target_phys_addr_t base,
|
static inline DeviceState *milkymist_uart_create(target_phys_addr_t base,
|
||||||
qemu_irq rx_irq, qemu_irq tx_irq)
|
qemu_irq irq)
|
||||||
{
|
{
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
|
|
||||||
dev = qdev_create(NULL, "milkymist-uart");
|
dev = qdev_create(NULL, "milkymist-uart");
|
||||||
qdev_init_nofail(dev);
|
qdev_init_nofail(dev);
|
||||||
sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
|
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), 0, irq);
|
||||||
sysbus_connect_irq(sysbus_from_qdev(dev), 1, tx_irq);
|
|
||||||
|
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
@ -30,19 +30,53 @@
|
|||||||
enum {
|
enum {
|
||||||
R_RXTX = 0,
|
R_RXTX = 0,
|
||||||
R_DIV,
|
R_DIV,
|
||||||
|
R_STAT,
|
||||||
|
R_CTRL,
|
||||||
|
R_DBG,
|
||||||
R_MAX
|
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 {
|
struct MilkymistUartState {
|
||||||
SysBusDevice busdev;
|
SysBusDevice busdev;
|
||||||
CharDriverState *chr;
|
CharDriverState *chr;
|
||||||
qemu_irq rx_irq;
|
qemu_irq irq;
|
||||||
qemu_irq tx_irq;
|
|
||||||
|
|
||||||
uint32_t regs[R_MAX];
|
uint32_t regs[R_MAX];
|
||||||
};
|
};
|
||||||
typedef struct MilkymistUartState MilkymistUartState;
|
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)
|
static uint32_t uart_read(void *opaque, target_phys_addr_t addr)
|
||||||
{
|
{
|
||||||
MilkymistUartState *s = opaque;
|
MilkymistUartState *s = opaque;
|
||||||
@ -51,7 +85,12 @@ static uint32_t uart_read(void *opaque, target_phys_addr_t addr)
|
|||||||
addr >>= 2;
|
addr >>= 2;
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case R_RXTX:
|
case R_RXTX:
|
||||||
|
r = s->regs[addr];
|
||||||
|
break;
|
||||||
case R_DIV:
|
case R_DIV:
|
||||||
|
case R_STAT:
|
||||||
|
case R_CTRL:
|
||||||
|
case R_DBG:
|
||||||
r = s->regs[addr];
|
r = s->regs[addr];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -79,18 +118,26 @@ static void uart_write(void *opaque, target_phys_addr_t addr, uint32_t value)
|
|||||||
if (s->chr) {
|
if (s->chr) {
|
||||||
qemu_chr_fe_write(s->chr, &ch, 1);
|
qemu_chr_fe_write(s->chr, &ch, 1);
|
||||||
}
|
}
|
||||||
trace_milkymist_uart_pulse_irq_tx();
|
s->regs[R_STAT] |= STAT_TX_EVT;
|
||||||
qemu_irq_pulse(s->tx_irq);
|
|
||||||
break;
|
break;
|
||||||
case R_DIV:
|
case R_DIV:
|
||||||
|
case R_CTRL:
|
||||||
|
case R_DBG:
|
||||||
s->regs[addr] = value;
|
s->regs[addr] = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case R_STAT:
|
||||||
|
/* write one to clear bits */
|
||||||
|
s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT));
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
error_report("milkymist_uart: write access to unknown register 0x"
|
error_report("milkymist_uart: write access to unknown register 0x"
|
||||||
TARGET_FMT_plx, addr << 2);
|
TARGET_FMT_plx, addr << 2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uart_update_irq(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CPUReadMemoryFunc * const uart_read_fn[] = {
|
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;
|
MilkymistUartState *s = opaque;
|
||||||
|
|
||||||
|
assert(!(s->regs[R_STAT] & STAT_RX_EVT));
|
||||||
|
|
||||||
|
s->regs[R_STAT] |= STAT_RX_EVT;
|
||||||
s->regs[R_RXTX] = *buf;
|
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)
|
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)
|
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++) {
|
for (i = 0; i < R_MAX; i++) {
|
||||||
s->regs[i] = 0;
|
s->regs[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* THRE is always set */
|
||||||
|
s->regs[R_STAT] = STAT_THRE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int milkymist_uart_init(SysBusDevice *dev)
|
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);
|
MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev);
|
||||||
int uart_regs;
|
int uart_regs;
|
||||||
|
|
||||||
sysbus_init_irq(dev, &s->rx_irq);
|
sysbus_init_irq(dev, &s->irq);
|
||||||
sysbus_init_irq(dev, &s->tx_irq);
|
|
||||||
|
|
||||||
uart_regs = cpu_register_io_memory(uart_read_fn, uart_write_fn, s,
|
uart_regs = cpu_register_io_memory(uart_read_fn, uart_write_fn, s,
|
||||||
DEVICE_NATIVE_ENDIAN);
|
DEVICE_NATIVE_ENDIAN);
|
||||||
|
@ -146,7 +146,7 @@ milkymist_init(ram_addr_t ram_size_not_used,
|
|||||||
exit(1);
|
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],
|
milkymist_sysctl_create(0x60001000, irq[2], irq[3], irq[4],
|
||||||
80000000, 0x10014d31, 0x0000041f, 0x00000001);
|
80000000, 0x10014d31, 0x0000041f, 0x00000001);
|
||||||
milkymist_hpdmc_create(0x60002000);
|
milkymist_hpdmc_create(0x60002000);
|
||||||
|
@ -444,8 +444,8 @@ milkymist_tmu2_pulse_irq(void) "Pulse IRQ"
|
|||||||
# hw/milkymist-uart.c
|
# hw/milkymist-uart.c
|
||||||
milkymist_uart_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
|
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_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x"
|
||||||
milkymist_uart_pulse_irq_rx(void) "Pulse IRQ RX"
|
milkymist_uart_raise_irq(void) "Raise IRQ"
|
||||||
milkymist_uart_pulse_irq_tx(void) "Pulse IRQ TX"
|
milkymist_uart_lower_irq(void) "Lower IRQ"
|
||||||
|
|
||||||
# hw/milkymist-vgafb.c
|
# hw/milkymist-vgafb.c
|
||||||
milkymist_vgafb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
|
milkymist_vgafb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x"
|
||||||
|
Loading…
Reference in New Issue
Block a user