aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2012-07-04 11:18:43 +0000
committerPeter Maydell <peter.maydell@linaro.org>2012-07-25 13:33:14 +0100
commit38718363127eb9b299d57fa337cc9d2fd20ae3dc (patch)
tree126b2a54dca7882dc819cf36f6bc3a9051abd808
parentb9a27c40902d8d51eb07beed0aa85776fc0b84fe (diff)
downloadqemu-arm-38718363127eb9b299d57fa337cc9d2fd20ae3dc.tar.gz
hw/omap_uart.c: Refactor register access mode tests
The OMAP UART provides different views of the registers depending on the access mode specified by the value in the LCR register. Refactor this to use an enumeration indicating the current mode rather than doing checks of the cache LCR value everywhere. Similarly, pull out into a function the check of whether registers 0x18/0x1c are in TCR/TLR mode. Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--hw/omap_uart.c50
1 files changed, 35 insertions, 15 deletions
diff --git a/hw/omap_uart.c b/hw/omap_uart.c
index bd159b4694..8f0ae4e99a 100644
--- a/hw/omap_uart.c
+++ b/hw/omap_uart.c
@@ -49,7 +49,13 @@ struct omap_uart_s {
qemu_irq tx_drq;
qemu_irq rx_drq;
- uint8_t lcr_cache;
+ /* Register access mode, which affects what registers you see */
+ enum {
+ regs_operational,
+ regs_config_a,
+ regs_config_b
+ } access_mode;
+
uint8_t eblr;
uint8_t syscontrol;
uint8_t wkup;
@@ -67,6 +73,14 @@ struct omap_uart_s {
uint8_t xon[2], xoff[2];
};
+static int tcr_tlr_mode(struct omap_uart_s *s)
+{
+ /* Return true if registers 0x18 and 0x1c are TCR/TLR
+ * (as opposed to SPR/MSR/XOFF)
+ */
+ return (s->efr & 0x10) && (s->mcr_cache & 0x40);
+}
+
static void omap_uart_reset(DeviceState *qdev)
{
struct omap_uart_s *s = FROM_SYSBUS(struct omap_uart_s,
@@ -78,7 +92,7 @@ static void omap_uart_reset(DeviceState *qdev)
s->clksel = 0;
s->blr = 0x40;
s->acreg = 0;
- s->lcr_cache = 0;
+ s->access_mode = regs_operational;
s->mcr_cache = 0;
s->tcr = 0x0f;
@@ -99,13 +113,13 @@ static uint64_t omap_uart_read(void *opaque, target_phys_addr_t addr,
case 0x0c:
return s->serial_ops->read(s->serial, addr, size);
case 0x08:
- if (s->lcr_cache == 0xbf) {
+ if (s->access_mode == regs_config_b) {
return s->efr;
}
return s->serial_ops->read(s->serial, addr, size);
case 0x10:
case 0x14:
- if (s->lcr_cache == 0xbf) {
+ if (s->access_mode == regs_config_b) {
return s->xon[(addr & 7) >> 2];
} else if (addr == 0x10) {
return s->serial_ops->read(s->serial, addr, size)
@@ -114,10 +128,10 @@ static uint64_t omap_uart_read(void *opaque, target_phys_addr_t addr,
return s->serial_ops->read(s->serial, addr, size);
case 0x18:
case 0x1c:
- if ((s->efr & 0x10) && (s->mcr_cache & 0x40)) {
+ if (tcr_tlr_mode(s)) {
return (addr == 0x18) ? s->tcr : s->tlr;
}
- if (s->lcr_cache == 0xbf) {
+ if (s->access_mode == regs_config_b) {
return s->xoff[(addr & 7) >> 2];
}
return s->serial_ops->read(s->serial, addr, size);
@@ -134,12 +148,12 @@ static uint64_t omap_uart_read(void *opaque, target_phys_addr_t addr,
case 0x34: /* SFREGH */
return 0;
case 0x38: /* UASR/BLR */
- if ((s->lcr_cache & 0x80)) {
+ if (s->access_mode != regs_operational) {
return 0; /* FIXME: return correct autodetect value */
}
return s->blr;
case 0x3c: /* ACREG */
- return (s->lcr_cache & 0x80) ? 0 : s->acreg;
+ return (s->access_mode != regs_operational) ? 0 : s->acreg;
case 0x40: /* SCR */
return s->scr;
case 0x44: /* SSR */
@@ -175,19 +189,25 @@ static void omap_uart_write(void *opaque, target_phys_addr_t addr,
s->serial_ops->write(s->serial, addr, value, size);
break;
case 0x08:
- if (s->lcr_cache == 0xbf) {
+ if (s->access_mode == regs_config_b) {
s->efr = value;
} else {
s->serial_ops->write(s->serial, addr, value, size);
}
break;
case 0x0c:
- s->lcr_cache = value;
+ if ((value & 0xff) == 0xbf) {
+ s->access_mode = regs_config_b;
+ } else if (value & 0x80) {
+ s->access_mode = regs_config_a;
+ } else {
+ s->access_mode = regs_operational;
+ }
s->serial_ops->write(s->serial, addr, value, size);
break;
case 0x10:
case 0x14:
- if (s->lcr_cache == 0xbf) {
+ if (s->access_mode == regs_config_b) {
s->xon[(addr & 7) >> 2] = value;
} else {
if (addr == 0x10) {
@@ -198,13 +218,13 @@ static void omap_uart_write(void *opaque, target_phys_addr_t addr,
break;
case 0x18:
case 0x1c:
- if ((s->efr & 0x10) && (s->mcr_cache & 0x40)) {
+ if (tcr_tlr_mode(s)) {
if (addr == 0x18) {
s->tcr = value & 0xff;
} else {
s->tlr = value & 0xff;
}
- } else if (s->lcr_cache == 0xbf) {
+ } else if (s->access_mode == regs_config_b) {
s->xoff[(addr & 7) >> 2] = value;
} else {
s->serial_ops->write(s->serial, addr, value, size);
@@ -223,12 +243,12 @@ static void omap_uart_write(void *opaque, target_phys_addr_t addr,
/* ignored */
break;
case 0x38: /* BLR */
- if (!(s->lcr_cache & 0x80)) {
+ if (s->access_mode == regs_operational) {
s->blr = value & 0xc0;
}
break;
case 0x3c: /* ACREG */
- if (!(s->lcr_cache & 0x80)) {
+ if (s->access_mode == regs_operational) {
s->acreg = value & 0xff;
}
break;