All of lore.kernel.org
 help / color / mirror / Atom feed
* Designware UART bug
@ 2017-05-03 10:17 Olliver Schinagl
  2017-05-03 10:40 ` [linux-sunxi] " Chen-Yu Tsai
  0 siblings, 1 reply; 7+ messages in thread
From: Olliver Schinagl @ 2017-05-03 10:17 UTC (permalink / raw)
  To: jamie, tim.kryger; +Cc: linux-kernel, dev, Maxime Ripard

Hey Jamie,

Several years ago you wrote the glue-code [0] for the DW 8250 IP. Over 
the years various 'fixes' have been applied to resolve certain 'weird' 
problems that Tim tried to fix with [1].

After going over the datasheets and code with a comb several times now, 
I think I may have found one (of a few others) reasons and would like 
both your and Tim's thoughts here.

The current (and original) code [2] uses the register offset 0x1f for 
the UART_USR register.

I searched far and wide, various datasheet of physical uarts (8250 - 
16950) and some IP cores and none seem to have the USR (and specifically 
the USR[0] bit) register, so it seems to be specific to the DW_apb_uart. 
However looking at the only databook available to me [3] of the UART IP, 
I cannot seem to find anything at register offset 0x1f.

The platform I'm using uses the Allwinner A20 SoC, which also features 
the DW uart IP and also here, there is nothing at offset 0x1f.

The intended register IS however actually at 0x7c.

My question is thus twofold.

Why was 0x1f used? Is this specific to a certain (version) UART or is 
this a long uncaught typo.

Tim, assuming it is a typo, could this the cause which made you 
implement [1]? From what I understand, you keep writing the LCR until it 
takes.

Initially, the UART_IIR_BUSY check looked like this:
	if (serial8250_handle_irq(p, iir)) {
                 return 1;
         } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
                 /* Clear the USR and write the LCR again. */
                 (void)p->serial_in(p, d->usr_reg);
                 p->serial_out(p, UART_LCR, d->last_lcr);

                 return 1;
         }

what I'm missing here is, that if UART_IIR_BUSY is set, we have:
* check the d->usr_reg (UART_USR) bit 0
* wait until it becomes cleared (do not allow new data to be pushed out, 
optionally force the data to be pushed out)
* write LCR register (and check if it took (and no longer loop over the 
LCR to see if the values stuck, in theory).
* if we never get un-busy, something is wrong?

All of this btw is currently moot anyway, as the only way to get into 
the (else) if, is if serial8250_handle_irq returns false. And from what 
I can see, this is only if iir == UART_IIR_NO_IRQ, in which case we 
never ever clear the USR and thus never ever clear the UART_IIR_BUSY flag.

Olliver


[0] 
https://github.com/torvalds/linux/commit/6b1a98d1c4851235d9b6764b3f7b7db7909fc760

[1] 
https://github.com/torvalds/linux/commit/c49436b657d0a56a6ad90d14a7c3041add7cf64d

[2] 
https://github.com/torvalds/linux/commit/6b1a98d1c4851235d9b6764b3f7b7db7909fc760#diff-d6e619fc4c51febf7880632fde5d0208R63

[3] http://linux-sunxi.org/images/d/d2/Dw_apb_uart_db.pdf

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2017-05-04  8:36 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-03 10:17 Designware UART bug Olliver Schinagl
2017-05-03 10:40 ` [linux-sunxi] " Chen-Yu Tsai
2017-05-03 11:26   ` Olliver Schinagl
2017-05-03 14:22     ` Tim Kryger
2017-05-03 15:40       ` Olliver Schinagl
2017-05-04  3:51         ` Tim Kryger
2017-05-04  8:35           ` Olliver Schinagl

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.