aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuha Riihimäki <juha.riihimaki@nokia.com>2012-07-04 11:18:42 +0000
committerPeter Maydell <peter.maydell@linaro.org>2012-07-25 13:33:02 +0100
commit11aef512c686a953edf09d05ea49736486372b75 (patch)
tree20aecb1287547db69ef4022d92ffa20dd67bd41b
parenta125213a23ca8a8db3cd56e53e13f63e7b8f840c (diff)
downloadqemu-arm-11aef512c686a953edf09d05ea49736486372b75.tar.gz
omap_uart updates
- convert to qdev - add missing registers FIXME this is badly broken due to serial init changing -- PMM Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
-rw-r--r--hw/omap.h15
-rw-r--r--hw/omap1.c64
-rw-r--r--hw/omap2.c73
-rw-r--r--hw/omap_uart.c266
-rw-r--r--hw/pc.h3
-rw-r--r--hw/serial.c28
6 files changed, 326 insertions, 123 deletions
diff --git a/hw/omap.h b/hw/omap.h
index d1115432f7..bd902ea3a5 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -870,18 +870,7 @@ struct omap_synctimer_s *omap_synctimer_init(struct omap_target_agent_s *ta,
struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk);
void omap_synctimer_reset(struct omap_synctimer_s *s);
-struct omap_uart_s;
-struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
- qemu_irq irq, omap_clk fclk, omap_clk iclk,
- qemu_irq txdma, qemu_irq rxdma,
- const char *label, CharDriverState *chr);
-struct omap_uart_s *omap2_uart_init(MemoryRegion *sysmem,
- struct omap_target_agent_s *ta,
- qemu_irq irq, omap_clk fclk, omap_clk iclk,
- qemu_irq txdma, qemu_irq rxdma,
- const char *label, CharDriverState *chr);
-void omap_uart_reset(struct omap_uart_s *s);
-void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr,
+void omap_uart_attach(DeviceState *qdev, CharDriverState *chr,
const char *label);
struct omap_mpuio_s;
@@ -1047,7 +1036,7 @@ struct omap_mpu_state_s {
unsigned long sram_size;
/* MPUI-TIPB peripherals */
- struct omap_uart_s *uart[3];
+ DeviceState *uart[4];
DeviceState *gpio;
diff --git a/hw/omap1.c b/hw/omap1.c
index ad60cc4919..73dc57e6ea 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -3687,9 +3687,6 @@ static void omap1_mpu_reset(void *opaque)
omap_dpll_reset(mpu->dpll[0]);
omap_dpll_reset(mpu->dpll[1]);
omap_dpll_reset(mpu->dpll[2]);
- omap_uart_reset(mpu->uart[0]);
- omap_uart_reset(mpu->uart[1]);
- omap_uart_reset(mpu->uart[2]);
omap_mmc_reset(mpu->mmc);
omap_mpuio_reset(mpu->mpuio);
omap_uwire_reset(mpu->microwire);
@@ -3932,27 +3929,46 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
omap_tcmi_init(system_memory, 0xfffecc00, s);
- s->uart[0] = omap_uart_init(0xfffb0000,
- qdev_get_gpio_in(s->ih[1], OMAP_INT_UART1),
- omap_findclk(s, "uart1_ck"),
- omap_findclk(s, "uart1_ck"),
- s->drq[OMAP_DMA_UART1_TX], s->drq[OMAP_DMA_UART1_RX],
- "uart1",
- serial_hds[0]);
- s->uart[1] = omap_uart_init(0xfffb0800,
- qdev_get_gpio_in(s->ih[1], OMAP_INT_UART2),
- omap_findclk(s, "uart2_ck"),
- omap_findclk(s, "uart2_ck"),
- s->drq[OMAP_DMA_UART2_TX], s->drq[OMAP_DMA_UART2_RX],
- "uart2",
- serial_hds[0] ? serial_hds[1] : NULL);
- s->uart[2] = omap_uart_init(0xfffb9800,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_UART3),
- omap_findclk(s, "uart3_ck"),
- omap_findclk(s, "uart3_ck"),
- s->drq[OMAP_DMA_UART3_TX], s->drq[OMAP_DMA_UART3_RX],
- "uart3",
- serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
+ s->uart[0] = qdev_create(NULL, "omap_uart");
+ s->uart[0]->id = "uart1";
+ qdev_prop_set_uint32(s->uart[0], "mmio_size", 0x400);
+ qdev_prop_set_uint32(s->uart[0], "baudrate",
+ omap_clk_getrate(omap_findclk(s, "uart1_ck")) / 16);
+ qdev_prop_set_chr(s->uart[0], "chardev", serial_hds[0]);
+ qdev_init_nofail(s->uart[0]);
+ busdev = sysbus_from_qdev(s->uart[0]);
+ sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[1], OMAP_INT_UART1));
+ sysbus_connect_irq(busdev, 1, s->drq[OMAP_DMA_UART1_TX]);
+ sysbus_connect_irq(busdev, 2, s->drq[OMAP_DMA_UART1_RX]);
+ sysbus_mmio_map(busdev, 0, 0xfffb0000);
+
+ s->uart[1] = qdev_create(NULL, "omap_uart");
+ s->uart[1]->id = "uart2";
+ qdev_prop_set_uint32(s->uart[1], "mmio_size", 0x400);
+ qdev_prop_set_uint32(s->uart[1], "baudrate",
+ omap_clk_getrate(omap_findclk(s, "uart2_ck")) / 16);
+ qdev_prop_set_chr(s->uart[1], "chardev",
+ serial_hds[0] ? serial_hds[1] : NULL);
+ qdev_init_nofail(s->uart[1]);
+ busdev = sysbus_from_qdev(s->uart[1]);
+ sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[1], OMAP_INT_UART2));
+ sysbus_connect_irq(busdev, 1, s->drq[OMAP_DMA_UART2_TX]);
+ sysbus_connect_irq(busdev, 2, s->drq[OMAP_DMA_UART2_RX]);
+ sysbus_mmio_map(busdev, 0, 0xfffb0800);
+
+ s->uart[2] = qdev_create(NULL, "omap_uart");
+ s->uart[2]->id = "uart3";
+ qdev_prop_set_uint32(s->uart[2], "mmio_size", 0x400);
+ qdev_prop_set_uint32(s->uart[2], "baudrate",
+ omap_clk_getrate(omap_findclk(s, "uart3_ck")) / 16);
+ qdev_prop_set_chr(s->uart[2], "chardev",
+ serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
+ qdev_init_nofail(s->uart[2]);
+ busdev = sysbus_from_qdev(s->uart[2]);
+ sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[0], OMAP_INT_UART3));
+ sysbus_connect_irq(busdev, 1, s->drq[OMAP_DMA_UART3_TX]);
+ sysbus_connect_irq(busdev, 2, s->drq[OMAP_DMA_UART3_RX]);
+ sysbus_mmio_map(busdev, 0, 0xfffb9800);
s->dpll[0] = omap_dpll_init(system_memory, 0xfffecf00,
omap_findclk(s, "dpll1"));
diff --git a/hw/omap2.c b/hw/omap2.c
index 5795d842eb..7850f53a7e 100644
--- a/hw/omap2.c
+++ b/hw/omap2.c
@@ -2216,9 +2216,6 @@ static void omap2_mpu_reset(void *opaque)
omap_sdrc_reset(mpu->sdrc);
omap_gpmc_reset(mpu->gpmc);
omap_dss_reset(mpu->dss);
- omap_uart_reset(mpu->uart[0]);
- omap_uart_reset(mpu->uart[1]);
- omap_uart_reset(mpu->uart[2]);
omap_mmc_reset(mpu->mmc);
cpu_reset(CPU(mpu->cpu));
}
@@ -2308,33 +2305,49 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem,
soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->sram),
OMAP2_SRAM_BASE, s->sram_size);
- s->uart[0] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 19),
- qdev_get_gpio_in(s->ih[0],
- OMAP_INT_24XX_UART1_IRQ),
- omap_findclk(s, "uart1_fclk"),
- omap_findclk(s, "uart1_iclk"),
- s->drq[OMAP24XX_DMA_UART1_TX],
- s->drq[OMAP24XX_DMA_UART1_RX],
- "uart1",
- serial_hds[0]);
- s->uart[1] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 20),
- qdev_get_gpio_in(s->ih[0],
- OMAP_INT_24XX_UART2_IRQ),
- omap_findclk(s, "uart2_fclk"),
- omap_findclk(s, "uart2_iclk"),
- s->drq[OMAP24XX_DMA_UART2_TX],
- s->drq[OMAP24XX_DMA_UART2_RX],
- "uart2",
- serial_hds[0] ? serial_hds[1] : NULL);
- s->uart[2] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 21),
- qdev_get_gpio_in(s->ih[0],
- OMAP_INT_24XX_UART3_IRQ),
- omap_findclk(s, "uart3_fclk"),
- omap_findclk(s, "uart3_iclk"),
- s->drq[OMAP24XX_DMA_UART3_TX],
- s->drq[OMAP24XX_DMA_UART3_RX],
- "uart3",
- serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
+ s->uart[0] = qdev_create(NULL, "omap_uart");
+ s->uart[0]->id = "uart1";
+ qdev_prop_set_uint32(s->uart[0], "mmio_size", 0x1000);
+ qdev_prop_set_uint32(s->uart[0], "baudrate",
+ omap_clk_getrate(omap_findclk(s, "uart1_fclk")) / 16);
+ qdev_prop_set_chr(s->uart[0], "chardev", serial_hds[0]);
+ qdev_init_nofail(s->uart[0]);
+ busdev = sysbus_from_qdev(s->uart[0]);
+ sysbus_connect_irq(busdev, 0,
+ qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_UART1_IRQ));
+ sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_UART1_TX]);
+ sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_UART1_RX]);
+ sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4ta(s->l4, 19), 0));
+
+ s->uart[1] = qdev_create(NULL, "omap_uart");
+ s->uart[1]->id = "uart2";
+ qdev_prop_set_uint32(s->uart[1], "mmio_size", 0x1000);
+ qdev_prop_set_uint32(s->uart[1], "baudrate",
+ omap_clk_getrate(omap_findclk(s, "uart2_fclk")) / 16);
+ qdev_prop_set_chr(s->uart[1], "chardev",
+ serial_hds[0] ? serial_hds[1] : NULL);
+ qdev_init_nofail(s->uart[1]);
+ busdev = sysbus_from_qdev(s->uart[1]);
+ sysbus_connect_irq(busdev, 0,
+ qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_UART2_IRQ));
+ sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_UART2_TX]);
+ sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_UART2_RX]);
+ sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4ta(s->l4, 20), 0));
+
+ s->uart[2] = qdev_create(NULL, "omap_uart");
+ s->uart[2]->id = "uart3";
+ qdev_prop_set_uint32(s->uart[2], "mmio_size", 0x1000);
+ qdev_prop_set_uint32(s->uart[2], "baudrate",
+ omap_clk_getrate(omap_findclk(s, "uart3_fclk")) / 16);
+ qdev_prop_set_chr(s->uart[2], "chardev",
+ serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
+ qdev_init_nofail(s->uart[2]);
+ busdev = sysbus_from_qdev(s->uart[2]);
+ sysbus_connect_irq(busdev, 0,
+ qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_UART3_IRQ));
+ sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_UART3_TX]);
+ sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_UART3_RX]);
+ sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4ta(s->l4, 21), 0));
s->gptimer[0] = omap_gp_timer_init(omap_l4ta(s->l4, 7),
qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER1),
diff --git a/hw/omap_uart.c b/hw/omap_uart.c
index c7d3cb7c11..280b6fd505 100644
--- a/hw/omap_uart.c
+++ b/hw/omap_uart.c
@@ -23,16 +23,28 @@
/* We use pc-style serial ports. */
#include "pc.h"
#include "exec-memory.h"
+#include "sysbus.h"
+
+/* The OMAP UART functionality is similar to the TI16C752 rather than
+ * the 16550A. When the flag below is enabled, the code will however
+ * offer 'only' the basic 16550A emulation. */
+/* TODO: real functionality for the TI16C752 enhanced features. Note
+ * QEMU's SerialState emulation internally always uses a 16-byte FIFO
+ * whereas we would need a 64-byte FIFO for OMAP. */
+#define OMAP_UART_16550A
-/* UARTs */
struct omap_uart_s {
+ SysBusDevice busdev;
MemoryRegion iomem;
- target_phys_addr_t base;
+ CharDriverState *chr;
SerialState *serial; /* TODO */
- struct omap_target_agent_s *ta;
- omap_clk fclk;
- qemu_irq irq;
+ const MemoryRegionOps *serial_ops;
+ uint32_t mmio_size;
+ uint32_t baudrate;
+ qemu_irq tx_drq;
+ qemu_irq rx_drq;
+ uint8_t lcr_cache;
uint8_t eblr;
uint8_t syscontrol;
uint8_t wkup;
@@ -40,33 +52,39 @@ struct omap_uart_s {
uint8_t mdr[2];
uint8_t scr;
uint8_t clksel;
+ uint8_t blr;
+ uint8_t acreg;
+
+#ifndef OMAP_UART_16550A
+ uint8_t mcr_cache;
+ uint8_t efr;
+ uint8_t tcr;
+ uint8_t tlr;
+ uint8_t xon[2], xoff[2];
+#endif
};
-void omap_uart_reset(struct omap_uart_s *s)
+static void omap_uart_reset(DeviceState *qdev)
{
+ struct omap_uart_s *s = FROM_SYSBUS(struct omap_uart_s,
+ sysbus_from_qdev(qdev));
s->eblr = 0x00;
s->syscontrol = 0;
s->wkup = 0x3f;
s->cfps = 0x69;
s->clksel = 0;
-}
+ s->blr = 0x40;
+ s->acreg = 0;
+ s->lcr_cache = 0;
-struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
- qemu_irq irq, omap_clk fclk, omap_clk iclk,
- qemu_irq txdma, qemu_irq rxdma,
- const char *label, CharDriverState *chr)
-{
- struct omap_uart_s *s = (struct omap_uart_s *)
- g_malloc0(sizeof(struct omap_uart_s));
-
- s->base = base;
- s->fclk = fclk;
- s->irq = irq;
- s->serial = serial_mm_init(get_system_memory(), base, 2, irq,
- omap_clk_getrate(fclk)/16,
- chr ?: qemu_chr_new(label, "null", NULL),
- DEVICE_NATIVE_ENDIAN);
- return s;
+#ifndef OMAP_UART_16550A
+ s->mcr_cache = 0;
+ s->tcr = 0x0f;
+ s->tlr = 0;
+ s->efr = 0;
+ s->xon[0] = s->xon[1] = 0;
+ s->xoff[0] = s->xoff[1] = 0;
+#endif
}
static uint64_t omap_uart_read(void *opaque, target_phys_addr_t addr,
@@ -74,15 +92,59 @@ static uint64_t omap_uart_read(void *opaque, target_phys_addr_t addr,
{
struct omap_uart_s *s = (struct omap_uart_s *) opaque;
- if (size == 4) {
- return omap_badwidth_read8(opaque, addr);
- }
-
switch (addr) {
+ case 0x00:
+ case 0x04:
+ case 0x0c:
+ return s->serial_ops->read(s->serial, addr, size);
+ case 0x08:
+#ifndef OMAP_UART_16550A
+ if (s->lcr_cache == 0xbf) {
+ return s->efr;
+ }
+#endif
+ return s->serial_ops->read(s->serial, addr, size);
+ case 0x10:
+ case 0x14:
+#ifndef OMAP_UART_16550A
+ if (s->lcr_cache == 0xbf) {
+ return s->xon[(addr & 7) >> 2];
+ } else if (addr == 0x10) {
+ return s->serial_ops->read(s->serial, addr, size)
+ | (s->mcr_cache & 0xe0);
+ }
+#endif
+ return s->serial_ops->read(s->serial, addr, size);
+ case 0x18:
+ case 0x1c:
+#ifndef OMAP_UART_16550A
+ if ((s->efr & 0x10) && (s->mcr_cache & 0x40)) {
+ return (addr == 0x18) ? s->tcr : s->tlr;
+ }
+ if (s->lcr_cache == 0xbf) {
+ return s->xoff[(addr & 7) >> 2];
+ }
+#endif
+ return s->serial_ops->read(s->serial, addr, size);
case 0x20: /* MDR1 */
return s->mdr[0];
case 0x24: /* MDR2 */
return s->mdr[1];
+ case 0x28: /* SFLSR */
+ return 0;
+ case 0x2c: /* RESUME */
+ return 0;
+ case 0x30: /* SFREGL */
+ return 0;
+ case 0x34: /* SFREGH */
+ return 0;
+ case 0x38: /* UASR/BLR */
+ if ((s->lcr_cache & 0x80)) {
+ return 0; /* FIXME: return correct autodetect value */
+ }
+ return s->blr;
+ case 0x3c: /* ACREG */
+ return (s->lcr_cache & 0x80) ? 0 : s->acreg;
case 0x40: /* SCR */
return s->scr;
case 0x44: /* SSR */
@@ -112,35 +174,99 @@ static void omap_uart_write(void *opaque, target_phys_addr_t addr,
{
struct omap_uart_s *s = (struct omap_uart_s *) opaque;
- if (size == 4) {
- return omap_badwidth_write8(opaque, addr, value);
- }
-
switch (addr) {
+ case 0x00:
+ case 0x04:
+ s->serial_ops->write(s->serial, addr, value, size);
+ break;
+ case 0x08:
+#ifndef OMAP_UART_16550A
+ if (s->lcr_cache == 0xbf) {
+ s->efr = value;
+ } else
+#endif
+ s->serial_ops->write(s->serial, addr, value, size);
+ break;
+ case 0x0c:
+ s->lcr_cache = value;
+ s->serial_ops->write(s->serial, addr, value, size);
+ break;
+ case 0x10:
+ case 0x14:
+#ifndef OMAP_UART_16550A
+ if (s->lcr_cache == 0xbf) {
+ s->xon[(addr & 7) >> 2] = value;
+ } else {
+ if (addr == 0x10) {
+ s->mcr_cache = value & 0x7f;
+ }
+#endif
+ s->serial_ops->write(s->serial, addr, value, size);
+#ifndef OMAP_UART_16550A
+ }
+#endif
+ break;
+ case 0x18:
+ case 0x1c:
+#ifndef OMAP_UART_16550A
+ if ((s->efr & 0x10) && (s->mcr_cache & 0x40)) {
+ if (addr == 0x18) {
+ s->tcr = value & 0xff;
+ } else {
+ s->tlr = value & 0xff;
+ }
+ } else if (s->lcr_cache == 0xbf) {
+ s->xoff[(addr & 7) >> 2] = value;
+ } else
+#endif
+ s->serial_ops->write(s->serial, addr, value, size);
+ break;
case 0x20: /* MDR1 */
s->mdr[0] = value & 0x7f;
break;
case 0x24: /* MDR2 */
s->mdr[1] = value & 0xff;
break;
+ case 0x28: /* TXFLL */
+ case 0x2c: /* TXFLH */
+ case 0x30: /* RXFLL */
+ case 0x34: /* RXFLH */
+ /* ignored */
+ break;
+ case 0x38: /* BLR */
+ if (!(s->lcr_cache & 0x80)) {
+ s->blr = value & 0xc0;
+ }
+ break;
+ case 0x3c: /* ACREG */
+ if (!(s->lcr_cache & 0x80)) {
+ s->acreg = value & 0xff;
+ }
+ break;
case 0x40: /* SCR */
s->scr = value & 0xff;
break;
+ case 0x44: /* SSR */
+ OMAP_RO_REG(addr);
+ break;
case 0x48: /* EBLR (OMAP2) */
s->eblr = value & 0xff;
break;
case 0x4C: /* OSC_12M_SEL (OMAP1) */
s->clksel = value & 1;
break;
- case 0x44: /* SSR */
case 0x50: /* MVR */
- case 0x58: /* SYSS (OMAP2) */
OMAP_RO_REG(addr);
break;
case 0x54: /* SYSC (OMAP2) */
s->syscontrol = value & 0x1d;
- if (value & 2)
- omap_uart_reset(s);
+ if (value & 2) {
+ /* TODO: reset s->serial also. */
+ omap_uart_reset(&s->busdev.qdev);
+ }
+ break;
+ case 0x58: /* SYSS (OMAP2) */
+ OMAP_RO_REG(addr);
break;
case 0x5c: /* WER (OMAP2) */
s->wkup = value & 0x7f;
@@ -159,31 +285,65 @@ static const MemoryRegionOps omap_uart_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-struct omap_uart_s *omap2_uart_init(MemoryRegion *sysmem,
- struct omap_target_agent_s *ta,
- qemu_irq irq, omap_clk fclk, omap_clk iclk,
- qemu_irq txdma, qemu_irq rxdma,
- const char *label, CharDriverState *chr)
+static int omap_uart_init(SysBusDevice *busdev)
{
- target_phys_addr_t base = omap_l4_attach(ta, 0, NULL);
- struct omap_uart_s *s = omap_uart_init(base, irq,
- fclk, iclk, txdma, rxdma, label, chr);
+ struct omap_uart_s *s = FROM_SYSBUS(struct omap_uart_s, busdev);
+ if (!s->chr) {
+ s->chr = qemu_chr_new(busdev->qdev.id, "null", NULL);
+ }
+ /* TODO: DMA support. Current 16550A emulation does not emulate DMA mode
+ * transfers via TXRDY/RXRDY pins. We create DMA irq lines here for
+ * future use nevertheless. */
+ /* Nasty hackery because trying to extend an existing device is
+ * not really supported, and the serial driver isn't even qdev.
+ */
+ s->serial = serial_mm_init(NULL, 0, 2, NULL, s->baudrate, s->chr,
+ DEVICE_NATIVE_ENDIAN);
+ s->serial_ops = serial_get_memops(DEVICE_NATIVE_ENDIAN);
+ sysbus_init_irq(busdev, serial_get_irq(s->serial));
+ sysbus_init_irq(busdev, &s->tx_drq);
+ sysbus_init_irq(busdev, &s->rx_drq);
+ memory_region_init_io(&s->iomem, &omap_uart_ops, s, "omap_uart",
+ s->mmio_size);
+ sysbus_init_mmio(busdev, &s->iomem);
+ return 0;
+}
- memory_region_init_io(&s->iomem, &omap_uart_ops, s, "omap.uart", 0x100);
+static Property omap_uart_properties[] = {
+ DEFINE_PROP_UINT32("mmio_size", struct omap_uart_s, mmio_size, 0x400),
+ DEFINE_PROP_UINT32("baudrate", struct omap_uart_s, baudrate, 0),
+ DEFINE_PROP_CHR("chardev", struct omap_uart_s, chr),
+ DEFINE_PROP_END_OF_LIST()
+};
- s->ta = ta;
+static void omap_uart_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ k->init = omap_uart_init;
+ dc->props = omap_uart_properties;
+ dc->reset = omap_uart_reset;
+}
- memory_region_add_subregion(sysmem, base + 0x20, &s->iomem);
+static TypeInfo omap_uart_info = {
+ .name = "omap_uart",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct omap_uart_s),
+ .class_init = omap_uart_class_init,
+};
- return s;
+static void omap_uart_register_types(void)
+{
+ type_register_static(&omap_uart_info);
}
-void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr,
+void omap_uart_attach(DeviceState *qdev, CharDriverState *chr,
const char *label)
{
- /* TODO: Should reuse or destroy current s->serial */
- s->serial = serial_mm_init(get_system_memory(), s->base, 2, s->irq,
- omap_clk_getrate(s->fclk) / 16,
- chr ?: qemu_chr_new(label, "null", NULL),
- DEVICE_NATIVE_ENDIAN);
+ struct omap_uart_s *s = FROM_SYSBUS(struct omap_uart_s,
+ sysbus_from_qdev(qdev));
+ s->chr = chr ?: qemu_chr_new(label, "null", NULL);
+ serial_change_char_driver(s->serial, s->chr);
}
+
+type_init(omap_uart_register_types)
diff --git a/hw/pc.h b/hw/pc.h
index 31ccb6f495..9e7721b7a3 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -38,6 +38,9 @@ static inline bool serial_isa_init(ISABus *bus, int index,
}
void serial_set_frequency(SerialState *s, uint32_t frequency);
+void serial_change_char_driver(SerialState *s, CharDriverState *chr);
+const MemoryRegionOps *serial_get_memops(enum device_endian end);
+qemu_irq *serial_get_irq(SerialState *s);
/* parallel.c */
static inline bool parallel_init(ISABus *bus, int index, CharDriverState *chr)
diff --git a/hw/serial.c b/hw/serial.c
index a421d1e7bc..4a8226415a 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -879,14 +879,36 @@ SerialState *serial_mm_init(MemoryRegion *address_space,
serial_init_core(s);
vmstate_register(NULL, base, &vmstate_serial, s);
- memory_region_init_io(&s->io, &serial_mm_ops[end], s,
- "serial", 8 << it_shift);
- memory_region_add_subregion(address_space, base, &s->io);
+ if (address_space) {
+ memory_region_init_io(&s->io, &serial_mm_ops[end], s,
+ "serial", 8 << it_shift);
+ memory_region_add_subregion(address_space, base, &s->io);
+ }
serial_update_msl(s);
return s;
}
+void serial_change_char_driver(SerialState *s, CharDriverState *chr)
+{
+ /* TODO this is somewhat guesswork, and pretty ugly anyhow */
+ qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL);
+ s->chr = chr;
+ qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1,
+ serial_event, s);
+ serial_update_msl(s);
+}
+
+const MemoryRegionOps *serial_get_memops(enum device_endian end)
+{
+ return &serial_mm_ops[end];
+}
+
+qemu_irq *serial_get_irq(SerialState *s)
+{
+ return &s->irq;
+}
+
static Property serial_isa_properties[] = {
DEFINE_PROP_UINT32("index", ISASerialState, index, -1),
DEFINE_PROP_HEX32("iobase", ISASerialState, iobase, -1),