summary refs log tree commit diff stats
path: root/hw/char/escc.c
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2021-11-21 14:12:25 +0100
committerRichard Henderson <richard.henderson@linaro.org>2021-11-21 14:12:25 +0100
commitc5fbdd60cf1fb52f01bdfe342b6fa65d5343e1b1 (patch)
treee86a96d22f3b5244d2d82a2c95fb90c94da891f0 /hw/char/escc.c
parent8627edfb3f1fca24a96a0954148885c3241c10f8 (diff)
parent319e89cdc32096432b578152a47d0d156033b711 (diff)
downloadfocaccia-qemu-c5fbdd60cf1fb52f01bdfe342b6fa65d5343e1b1.tar.gz
focaccia-qemu-c5fbdd60cf1fb52f01bdfe342b6fa65d5343e1b1.zip
Merge tag 'qemu-sparc-20211121' of git://github.com/mcayland/qemu into staging
qemu-sparc queue

# gpg: Signature made Sun 21 Nov 2021 10:57:01 AM CET
# gpg:                using RSA key CC621AB98E82200D915CC9C45BC2C56FAE0F321F
# gpg:                issuer "mark.cave-ayland@ilande.co.uk"
# gpg: Good signature from "Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>" [full]

* tag 'qemu-sparc-20211121' of git://github.com/mcayland/qemu:
  escc: update the R_SPEC register SPEC_ALLSENT bit when writing to W_TXCTRL1
  escc: always set STATUS_TXEMPTY in R_STATUS on device reset

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'hw/char/escc.c')
-rw-r--r--hw/char/escc.c25
1 files changed, 25 insertions, 0 deletions
diff --git a/hw/char/escc.c b/hw/char/escc.c
index 0fce4f6324..8755d8d34f 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -354,6 +354,17 @@ static void escc_reset(DeviceState *d)
             cs->rregs[j] = 0;
             cs->wregs[j] = 0;
         }
+
+        /*
+         * ...but there is an exception. The "Transmit Interrupts and Transmit
+         * Buffer Empty Bit" section on page 50 of the ESCC datasheet says of
+         * the STATUS_TXEMPTY bit in R_STATUS: "After a hardware reset
+         * (including a hardware reset by software), or a channel reset, this
+         * bit is set to 1". The Sun PROM checks this bit early on startup and
+         * gets stuck in an infinite loop if it is not set.
+         */
+        cs->rregs[R_STATUS] |= STATUS_TXEMPTY;
+
         escc_reset_chn(cs);
     }
 }
@@ -575,6 +586,20 @@ static void escc_mem_write(void *opaque, hwaddr addr,
             s->wregs[s->reg] = val;
             break;
         case W_TXCTRL1:
+            s->wregs[s->reg] = val;
+            /*
+             * The ESCC datasheet states that SPEC_ALLSENT is always set in
+             * sync mode, and set in async mode when all characters have
+             * cleared the transmitter. Since writes to SERIAL_DATA use the
+             * blocking qemu_chr_fe_write_all() function to write each
+             * character, the guest can never see the state when async data
+             * is in the process of being transmitted so we can set this bit
+             * unconditionally regardless of the state of the W_TXCTRL1 mode
+             * bits.
+             */
+            s->rregs[R_SPEC] |= SPEC_ALLSENT;
+            escc_update_parameters(s);
+            break;
         case W_TXCTRL2:
             s->wregs[s->reg] = val;
             escc_update_parameters(s);