summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@orcam.me.uk>2026-05-06 23:42:31 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-05-22 11:52:33 +0200
commitca904f4b42355287bc5ce8b7550ebe909cda4c2c (patch)
treec2d56ca3c336a40f3ed760e2c336561ab9c04630
parent2e211723953f7740e54b53f3d3a0d5e351a5e223 (diff)
serial: dz: Fix bootconsole message clobbering at chip reset
In the DZ interface as implemented by the DC7085 gate array the serial transmitters are double buffered, meaning that at the time a transmitter is ready to accept the next character there is one in the transmit shift register still being sent to the line. Issuing a master clear at this time causes this character to be lost, so wait an extra amount of time sufficient for the transmit shift register to drain at 9600bps, which is the baud rate setting used by the firmware console. Mind the specified 1.4us TRDY recovery time in the course and continue using iob() as the completion barrier, since the platforms involved use a write buffer that can delay and combine writes, and reorder them with respect to reads regardless of the MMIO locations accessed and we still lack a platform-independent handler for that. When called from dz_serial_console_init() this is too early for fsleep() to work and even before lpj has been calculated and therefore the delay is actually not sufficient for the transmitter to drain and is merely a placeholder now. This will be addressed in a follow-up change. Fixes: e6ee512f5a77 ("dz.c: Resource management") Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk> Cc: stable@vger.kernel.org # v2.6.25+ Link: https://patch.msgid.link/alpine.DEB.2.21.2605062259080.46195@angie.orcam.me.uk Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/serial/dz.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c
index e53c54353c3e..d14a40e8cc0a 100644
--- a/drivers/tty/serial/dz.c
+++ b/drivers/tty/serial/dz.c
@@ -542,10 +542,31 @@ static int dz_encode_baud_rate(unsigned int baud)
static void dz_reset(struct dz_port *dport)
{
struct dz_mux *mux = dport->mux;
+ unsigned short tcr;
+ int loops = 10000;
if (mux->initialised)
return;
+ tcr = dz_in(dport, DZ_TCR);
+
+ /* Do not disturb any ongoing transmissions. */
+ if (dz_in(dport, DZ_CSR) & DZ_MSE) {
+ unsigned short csr, mask;
+
+ mask = tcr;
+ while ((mask & DZ_LNENB) && loops--) {
+ csr = dz_in(dport, DZ_CSR);
+ if (!(csr & DZ_TRDY))
+ continue;
+ mask &= ~(1 << ((csr & DZ_TLINE) >> 8));
+ dz_out(dport, DZ_TCR, mask);
+ iob();
+ udelay(2); /* 1.4us TRDY recovery. */
+ }
+ udelay(1200); /* Transmitter drain. */
+ }
+
dz_out(dport, DZ_CSR, DZ_CLR);
while (dz_in(dport, DZ_CSR) & DZ_CLR);
iob();