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:
Michael Walle 2011-08-11 00:13:23 +02:00
parent 27f930c5f0
commit fcfa339778
4 changed files with 68 additions and 15 deletions

View File

@ -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;
} }

View File

@ -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);

View File

@ -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);

View File

@ -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"