diff options
author | Juha Riihimäki <juha.riihimaki@nokia.com> | 2012-07-11 11:25:43 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2012-07-11 11:25:43 +0000 |
commit | 062f754c88d47e224822c1debdf66211557b7918 (patch) | |
tree | 15a925eefa3e7bba9140e304c8971dc2997bdfdf | |
parent | 6a914af4b7235719eda93bc1745aa165b040d90d (diff) |
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.h | 15 | ||||
-rw-r--r-- | hw/omap1.c | 64 | ||||
-rw-r--r-- | hw/omap2.c | 73 | ||||
-rw-r--r-- | hw/omap_uart.c | 266 | ||||
-rw-r--r-- | hw/pc.h | 3 | ||||
-rw-r--r-- | hw/serial.c | 28 |
6 files changed, 326 insertions, 123 deletions
@@ -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) @@ -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), |