2011-05-16 13:01:48

by Shreshtha Kumar SAHU

[permalink] [raw]
Subject: [PATCH 1/2] amba pl011: workaround for uart registers lockup

From: Shreshtha Kumar Sahu <[email protected]>

This workaround aims to break the deadlock situation
which raises during continuous transfer of data for long
duration over uart with hardware flow control. It is
observed that CTS interrupt cannot be cleared in uart
interrupt register (ICR). Hence further transfer over
uart gets blocked.

It is seen that during such deadlock condition ICR
don't get cleared even on multiple write. This leads
pass_counter to decrease and finally reach zero. This
can be taken as trigger point to run this UART_BT_WA.

Workaround backups the register configuration, does soft
reset of UART using BIT-0 of PRCC_K_SOFTRST_SET/CLEAR
registers and restores the registers.

This patch also provides support for uart init and exit
function calls if present.

Signed-off-by: Shreshtha Kumar Sahu <[email protected]>
---
drivers/tty/serial/amba-pl011.c | 123 ++++++++++++++++++++++++++++++++++++++-
include/linux/amba/serial.h | 3 +
2 files changed, 125 insertions(+), 1 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 8dc0541..f5f6831 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -50,6 +50,7 @@
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
+#include <linux/delay.h>

#include <asm/io.h>
#include <asm/sizes.h>
@@ -65,6 +66,30 @@
#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
#define UART_DUMMY_DR_RX (1 << 16)

+
+#define UART_WA_SAVE_NR 14
+
+static void pl011_lockup_wa(unsigned long data);
+static const u32 uart_wa_reg[UART_WA_SAVE_NR] = {
+ ST_UART011_DMAWM,
+ ST_UART011_TIMEOUT,
+ ST_UART011_LCRH_RX,
+ UART011_IBRD,
+ UART011_FBRD,
+ ST_UART011_LCRH_TX,
+ UART011_IFLS,
+ ST_UART011_XFCR,
+ ST_UART011_XON1,
+ ST_UART011_XON2,
+ ST_UART011_XOFF1,
+ ST_UART011_XOFF2,
+ UART011_CR,
+ UART011_IMSC
+};
+
+static u32 uart_wa_regdata[UART_WA_SAVE_NR];
+static DECLARE_TASKLET(pl011_lockup_tlet, pl011_lockup_wa, 0);
+
/* There is by now at least one vendor with differing details, so handle it */
struct vendor_data {
unsigned int ifls;
@@ -72,6 +97,7 @@ struct vendor_data {
unsigned int lcrh_tx;
unsigned int lcrh_rx;
bool oversampling;
+ bool interrupt_may_hang; /* vendor-specific */
bool dma_threshold;
};

@@ -90,9 +116,12 @@ static struct vendor_data vendor_st = {
.lcrh_tx = ST_UART011_LCRH_TX,
.lcrh_rx = ST_UART011_LCRH_RX,
.oversampling = true,
+ .interrupt_may_hang = true,
.dma_threshold = true,
};

+static struct uart_amba_port *amba_ports[UART_NR];
+
/* Deals with DMA transactions */

struct pl011_sgbuf {
@@ -132,6 +161,7 @@ struct uart_amba_port {
unsigned int lcrh_rx; /* vendor-specific */
bool autorts;
char type[12];
+ bool interrupt_may_hang; /* vendor-specific */
#ifdef CONFIG_DMA_ENGINE
/* DMA stuff */
bool using_tx_dma;
@@ -1008,6 +1038,68 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
#endif


+/*
+ * pl011_lockup_wa
+ * This workaround aims to break the deadlock situation
+ * when after long transfer over uart in hardware flow
+ * control, uart interrupt registers cannot be cleared.
+ * Hence uart transfer gets blocked.
+ *
+ * It is seen that during such deadlock condition ICR
+ * don't get cleared even on multiple write. This leads
+ * pass_counter to decrease and finally reach zero. This
+ * can be taken as trigger point to run this UART_BT_WA.
+ *
+ */
+static void pl011_lockup_wa(unsigned long data)
+{
+ struct uart_amba_port *uap = amba_ports[0];
+ void __iomem *base = uap->port.membase;
+ struct circ_buf *xmit = &uap->port.state->xmit;
+ struct tty_struct *tty = uap->port.state->port.tty;
+ int buf_empty_retries = 200;
+ int loop;
+
+ /* Stop HCI layer from submitting data for tx */
+ tty->hw_stopped = 1;
+ while (!uart_circ_empty(xmit)) {
+ if (buf_empty_retries-- == 0)
+ break;
+ udelay(100);
+ }
+
+ /* Backup registers */
+ for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
+ uart_wa_regdata[loop] = readl(base + uart_wa_reg[loop]);
+
+ /* Disable UART so that FIFO data is flushed out */
+ writew(0x00, uap->port.membase + UART011_CR);
+
+ /* Soft reset UART module */
+ if (uap->port.dev->platform_data) {
+ struct amba_pl011_data *plat;
+
+ plat = uap->port.dev->platform_data;
+ if (plat->reset)
+ plat->reset();
+ }
+
+ /* Restore registers */
+ for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
+ writew(uart_wa_regdata[loop] ,
+ uap->port.membase + uart_wa_reg[loop]);
+
+ /* Initialise the old status of the modem signals */
+ uap->old_status = readw(uap->port.membase + UART01x_FR) &
+ UART01x_FR_MODEM_ANY;
+
+ if (readl(base + UART011_MIS) & 0x2)
+ printk(KERN_EMERG "UART_BT_WA: ***FAILED***\n");
+
+ /* Start Tx/Rx */
+ tty->hw_stopped = 0;
+}
+
static void pl011_stop_tx(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -1158,8 +1250,11 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
if (status & UART011_TXIS)
pl011_tx_chars(uap);

- if (pass_counter-- == 0)
+ if (pass_counter-- == 0) {
+ if (uap->interrupt_may_hang)
+ tasklet_schedule(&pl011_lockup_tlet);
break;
+ }

status = readw(uap->port.membase + UART011_MIS);
} while (status != 0);
@@ -1339,6 +1434,14 @@ static int pl011_startup(struct uart_port *port)
writew(uap->im, uap->port.membase + UART011_IMSC);
spin_unlock_irq(&uap->port.lock);

+ if (uap->port.dev->platform_data) {
+ struct amba_pl011_data *plat;
+
+ plat = uap->port.dev->platform_data;
+ if (plat->init)
+ plat->init();
+ }
+
return 0;

clk_dis:
@@ -1394,6 +1497,15 @@ static void pl011_shutdown(struct uart_port *port)
* Shut down the clock producer
*/
clk_disable(uap->clk);
+
+ if (uap->port.dev->platform_data) {
+ struct amba_pl011_data *plat;
+
+ plat = uap->port.dev->platform_data;
+ if (plat->exit)
+ plat->exit();
+ }
+
}

static void
@@ -1700,6 +1812,14 @@ static int __init pl011_console_setup(struct console *co, char *options)
if (!uap)
return -ENODEV;

+ if (uap->port.dev->platform_data) {
+ struct amba_pl011_data *plat;
+
+ plat = uap->port.dev->platform_data;
+ if (plat->init)
+ plat->init();
+ }
+
uap->port.uartclk = clk_get_rate(uap->clk);

if (options)
@@ -1774,6 +1894,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
uap->lcrh_rx = vendor->lcrh_rx;
uap->lcrh_tx = vendor->lcrh_tx;
uap->fifosize = vendor->fifosize;
+ uap->interrupt_may_hang = vendor->interrupt_may_hang;
uap->port.dev = &dev->dev;
uap->port.mapbase = dev->res.start;
uap->port.membase = base;
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h
index 5479fdc..514ed45 100644
--- a/include/linux/amba/serial.h
+++ b/include/linux/amba/serial.h
@@ -201,6 +201,9 @@ struct amba_pl011_data {
bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
void *dma_rx_param;
void *dma_tx_param;
+ void (*init) (void);
+ void (*exit) (void);
+ void (*reset) (void);
};
#endif

--
1.7.2.dirty


2011-05-16 13:01:52

by Shreshtha Kumar SAHU

[permalink] [raw]
Subject: [PATCH 2/2] amba pl011: platform data for reg lockup and glitch

From: Shreshtha Kumar Sahu <[email protected]>

This patch provides platform data for following
- uart reset function to assist uart register lockup workaround

- init/exit function to fix glitch in the tx pin in tty_open
when tty port0 is opened a glitch is seen in the tx line
of uart0. This happens in __pl011_startup() when tx fifo
interrupt is provoked into asserting.
Now uart0 pins are enabled (alt function) only when init
is complete and turned back to gpio when closed.

Signed-off-by: Shreshtha Kumar Sahu <[email protected]>
---
arch/arm/mach-ux500/board-mop500-pins.c | 16 +++++++--
arch/arm/mach-ux500/board-mop500.c | 53 +++++++++++++++++++++++++++++++
2 files changed, 65 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c
index fd4cf1c..ceab640 100644
--- a/arch/arm/mach-ux500/board-mop500-pins.c
+++ b/arch/arm/mach-ux500/board-mop500-pins.c
@@ -110,10 +110,18 @@ static pin_cfg_t mop500_pins_common[] = {
GPIO168_KP_O0,

/* UART */
- GPIO0_U0_CTSn | PIN_INPUT_PULLUP,
- GPIO1_U0_RTSn | PIN_OUTPUT_HIGH,
- GPIO2_U0_RXD | PIN_INPUT_PULLUP,
- GPIO3_U0_TXD | PIN_OUTPUT_HIGH,
+ /* uart-0 pins gpio configuration should be
+ * kept intact to prevent glitch in tx line
+ * when tty dev is opened. Later these pins
+ * are configured to uart mop500_pins_uart0
+ *
+ * It will be replaced with uart configuration
+ * once the issue is solved.
+ */
+ GPIO0_GPIO | PIN_INPUT_PULLUP,
+ GPIO1_GPIO | PIN_OUTPUT_HIGH,
+ GPIO2_GPIO | PIN_INPUT_PULLUP,
+ GPIO3_GPIO | PIN_OUTPUT_LOW,

GPIO29_U2_RXD | PIN_INPUT_PULLUP,
GPIO30_U2_TXD | PIN_OUTPUT_HIGH,
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index 6e1907fa..e7bc61e 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -27,6 +27,7 @@
#include <linux/leds-lp5521.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
+#include <linux/delay.h>

#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -39,6 +40,7 @@
#include <mach/devices.h>
#include <mach/irqs.h>

+#include "pins-db8500.h"
#include "ste-dma40-db8500.h"
#include "devices-db8500.h"
#include "board-mop500.h"
@@ -391,12 +393,63 @@ static struct stedma40_chan_cfg uart2_dma_cfg_tx = {
};
#endif

+
+static pin_cfg_t mop500_pins_uart0[] = {
+ GPIO0_U0_CTSn | PIN_INPUT_PULLUP,
+ GPIO1_U0_RTSn | PIN_OUTPUT_HIGH,
+ GPIO2_U0_RXD | PIN_INPUT_PULLUP,
+ GPIO3_U0_TXD | PIN_OUTPUT_HIGH,
+};
+
+#define PRCC_K_SOFTRST_SET 0x18
+#define PRCC_K_SOFTRST_CLEAR 0x1C
+static void ux500_uart0_reset(void)
+{
+ void __iomem *prcc_rst_set, *prcc_rst_clr;
+
+ prcc_rst_set = (void __iomem *)IO_ADDRESS(U8500_CLKRST1_BASE +
+ PRCC_K_SOFTRST_SET);
+ prcc_rst_clr = (void __iomem *)IO_ADDRESS(U8500_CLKRST1_BASE +
+ PRCC_K_SOFTRST_CLEAR);
+
+ /* Activate soft reset PRCC_K_SOFTRST_CLEAR */
+ writel((readl(prcc_rst_clr) | 0x1), prcc_rst_clr);
+ udelay(1);
+
+ /* Release soft reset PRCC_K_SOFTRST_SET */
+ writel((readl(prcc_rst_set) | 0x1), prcc_rst_set);
+ udelay(1);
+}
+
+static void ux500_uart0_init(void)
+{
+ int ret;
+
+ ret = nmk_config_pins(mop500_pins_uart0,
+ ARRAY_SIZE(mop500_pins_uart0));
+ if (ret < 0)
+ pr_err("pl011: uart pins_enable failed\n");
+}
+
+static void ux500_uart0_exit(void)
+{
+ int ret;
+
+ ret = nmk_config_pins_sleep(mop500_pins_uart0,
+ ARRAY_SIZE(mop500_pins_uart0));
+ if (ret < 0)
+ pr_err("pl011: uart pins_disable failed\n");
+}
+
static struct amba_pl011_data uart0_plat = {
#ifdef CONFIG_STE_DMA40
.dma_filter = stedma40_filter,
.dma_rx_param = &uart0_dma_cfg_rx,
.dma_tx_param = &uart0_dma_cfg_tx,
#endif
+ .init = ux500_uart0_init,
+ .exit = ux500_uart0_exit,
+ .reset = ux500_uart0_reset,
};

static struct amba_pl011_data uart1_plat = {
--
1.7.2.dirty

2011-05-16 13:09:20

by Russell King

[permalink] [raw]
Subject: Re: [PATCH 2/2] amba pl011: platform data for reg lockup and glitch

On Mon, May 16, 2011 at 06:31:19PM +0530, Shreshtha Kumar SAHU wrote:
> From: Shreshtha Kumar Sahu <[email protected]>
>
> This patch provides platform data for following
> - uart reset function to assist uart register lockup workaround
>
> - init/exit function to fix glitch in the tx pin in tty_open
> when tty port0 is opened a glitch is seen in the tx line
> of uart0. This happens in __pl011_startup() when tx fifo
> interrupt is provoked into asserting.

I was trying to work out where that is, but i can't find this function.
Is your patch against a different version of the driver?

--
Russell King
Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/
maintainer of:

2011-05-16 14:01:02

by Shreshtha Kumar SAHU

[permalink] [raw]
Subject: Re: [PATCH 2/2] amba pl011: platform data for reg lockup and glitch

On Mon, May 16, 2011 at 15:09:05 +0200, Russell King wrote:
> On Mon, May 16, 2011 at 06:31:19PM +0530, Shreshtha Kumar SAHU wrote:
> > From: Shreshtha Kumar Sahu <[email protected]>
> >
> > This patch provides platform data for following
> > - uart reset function to assist uart register lockup workaround
> >
> > - init/exit function to fix glitch in the tx pin in tty_open
> > when tty port0 is opened a glitch is seen in the tx line
> > of uart0. This happens in __pl011_startup() when tx fifo
> > interrupt is provoked into asserting.
>
> I was trying to work out where that is, but i can't find this function.
> Is your patch against a different version of the driver?
sorry, the function names in commit message is wrong by mistake.
It should be - "This happens in pl011_startup() when tx
fifo interrupt is provoked into asserting."
I will send out a new patch with corrected commit mesaage.

>
> --
> Russell King
> Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/
> maintainer of:

BR,
Shreshtha

2011-05-16 14:05:56

by Russell King

[permalink] [raw]
Subject: Re: [PATCH 2/2] amba pl011: platform data for reg lockup and glitch

On Mon, May 16, 2011 at 07:30:46PM +0530, Shreshtha Kumar SAHU wrote:
> On Mon, May 16, 2011 at 15:09:05 +0200, Russell King wrote:
> > On Mon, May 16, 2011 at 06:31:19PM +0530, Shreshtha Kumar SAHU wrote:
> > > From: Shreshtha Kumar Sahu <[email protected]>
> > >
> > > This patch provides platform data for following
> > > - uart reset function to assist uart register lockup workaround
> > >
> > > - init/exit function to fix glitch in the tx pin in tty_open
> > > when tty port0 is opened a glitch is seen in the tx line
> > > of uart0. This happens in __pl011_startup() when tx fifo
> > > interrupt is provoked into asserting.
> >
> > I was trying to work out where that is, but i can't find this function.
> > Is your patch against a different version of the driver?
> sorry, the function names in commit message is wrong by mistake.
> It should be - "This happens in pl011_startup() when tx
> fifo interrupt is provoked into asserting."
> I will send out a new patch with corrected commit mesaage.

Have you tracked down why this happens?

Is it the switching into and out of loopback mode, or does loopback mode
not prevent the transmit pin toggling?

--
Russell King
Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/
maintainer of:

2011-05-16 14:15:52

by Shreshtha Kumar SAHU

[permalink] [raw]
Subject: Re: [PATCH 2/2] amba pl011: platform data for reg lockup and glitch

On Mon, May 16, 2011 at 16:05:41 +0200, Russell King wrote:
> On Mon, May 16, 2011 at 07:30:46PM +0530, Shreshtha Kumar SAHU wrote:
> > On Mon, May 16, 2011 at 15:09:05 +0200, Russell King wrote:
> > > On Mon, May 16, 2011 at 06:31:19PM +0530, Shreshtha Kumar SAHU wrote:
> > > > From: Shreshtha Kumar Sahu <[email protected]>
> > > >
> > > > This patch provides platform data for following
> > > > - uart reset function to assist uart register lockup workaround
> > > >
> > > > - init/exit function to fix glitch in the tx pin in tty_open
> > > > when tty port0 is opened a glitch is seen in the tx line
> > > > of uart0. This happens in __pl011_startup() when tx fifo
> > > > interrupt is provoked into asserting.
> > >
> > > I was trying to work out where that is, but i can't find this function.
> > > Is your patch against a different version of the driver?
> > sorry, the function names in commit message is wrong by mistake.
> > It should be - "This happens in pl011_startup() when tx
> > fifo interrupt is provoked into asserting."
> > I will send out a new patch with corrected commit mesaage.
>
> Have you tracked down why this happens?
>
> Is it the switching into and out of loopback mode, or does loopback mode
> not prevent the transmit pin toggling?
As I tried to get the cause for it, I found it is not due to switching in
and out of loopback mode. It was found to be default behaviour of the hardware.
Even in loopback mode data is transmitted out to pins.
>
> --
> Russell King
> Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/
> maintainer of:

2011-05-16 17:31:58

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH 1/2] amba pl011: workaround for uart registers lockup

On Mon, May 16, 2011 at 06:31:18PM +0530, Shreshtha Kumar SAHU wrote:
> From: Shreshtha Kumar Sahu <[email protected]>
>
> This workaround aims to break the deadlock situation
> which raises during continuous transfer of data for long
> duration over uart with hardware flow control. It is
> observed that CTS interrupt cannot be cleared in uart
> interrupt register (ICR). Hence further transfer over
> uart gets blocked.
>
> It is seen that during such deadlock condition ICR
> don't get cleared even on multiple write. This leads
> pass_counter to decrease and finally reach zero. This
> can be taken as trigger point to run this UART_BT_WA.
>
> Workaround backups the register configuration, does soft
> reset of UART using BIT-0 of PRCC_K_SOFTRST_SET/CLEAR
> registers and restores the registers.
>
> This patch also provides support for uart init and exit
> function calls if present.
>
> Signed-off-by: Shreshtha Kumar Sahu <[email protected]>

Please always run your patches through scripts/checkpatch.pl so we don't
end up telling you to fix up the same obvious things that this tool
would tell you needs to be fixed...

thanks,

greg k-h

2011-05-17 05:20:56

by Shreshtha Kumar SAHU

[permalink] [raw]
Subject: [PATCHv2 1/2] amba pl011: workaround for uart registers lockup

From: Shreshtha Kumar Sahu <[email protected]>

This workaround aims to break the deadlock situation
which raises during continuous transfer of data for long
duration over uart with hardware flow control. It is
observed that CTS interrupt cannot be cleared in uart
interrupt register (ICR). Hence further transfer over
uart gets blocked.

It is seen that during such deadlock condition ICR
don't get cleared even on multiple write. This leads
pass_counter to decrease and finally reach zero. This
can be taken as trigger point to run this UART_BT_WA.

Workaround backups the register configuration, does soft
reset of UART using BIT-0 of PRCC_K_SOFTRST_SET/CLEAR
registers and restores the registers.

This patch also provides support for uart init and exit
function calls if present.

Signed-off-by: Shreshtha Kumar Sahu <[email protected]>
---
changes in v2:
fixed checkpatch errors
corrected comment of function pl011_lockup_wa

drivers/tty/serial/amba-pl011.c | 123 ++++++++++++++++++++++++++++++++++++++-
include/linux/amba/serial.h | 3 +
2 files changed, 125 insertions(+), 1 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 8dc0541..e3b9d93 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -50,6 +50,7 @@
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
+#include <linux/delay.h>

#include <asm/io.h>
#include <asm/sizes.h>
@@ -65,6 +66,30 @@
#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
#define UART_DUMMY_DR_RX (1 << 16)

+
+#define UART_WA_SAVE_NR 14
+
+static void pl011_lockup_wa(unsigned long data);
+static const u32 uart_wa_reg[UART_WA_SAVE_NR] = {
+ ST_UART011_DMAWM,
+ ST_UART011_TIMEOUT,
+ ST_UART011_LCRH_RX,
+ UART011_IBRD,
+ UART011_FBRD,
+ ST_UART011_LCRH_TX,
+ UART011_IFLS,
+ ST_UART011_XFCR,
+ ST_UART011_XON1,
+ ST_UART011_XON2,
+ ST_UART011_XOFF1,
+ ST_UART011_XOFF2,
+ UART011_CR,
+ UART011_IMSC
+};
+
+static u32 uart_wa_regdata[UART_WA_SAVE_NR];
+static DECLARE_TASKLET(pl011_lockup_tlet, pl011_lockup_wa, 0);
+
/* There is by now at least one vendor with differing details, so handle it */
struct vendor_data {
unsigned int ifls;
@@ -72,6 +97,7 @@ struct vendor_data {
unsigned int lcrh_tx;
unsigned int lcrh_rx;
bool oversampling;
+ bool interrupt_may_hang; /* vendor-specific */
bool dma_threshold;
};

@@ -90,9 +116,12 @@ static struct vendor_data vendor_st = {
.lcrh_tx = ST_UART011_LCRH_TX,
.lcrh_rx = ST_UART011_LCRH_RX,
.oversampling = true,
+ .interrupt_may_hang = true,
.dma_threshold = true,
};

+static struct uart_amba_port *amba_ports[UART_NR];
+
/* Deals with DMA transactions */

struct pl011_sgbuf {
@@ -132,6 +161,7 @@ struct uart_amba_port {
unsigned int lcrh_rx; /* vendor-specific */
bool autorts;
char type[12];
+ bool interrupt_may_hang; /* vendor-specific */
#ifdef CONFIG_DMA_ENGINE
/* DMA stuff */
bool using_tx_dma;
@@ -1008,6 +1038,68 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
#endif


+/*
+ * pl011_lockup_wa
+ * This workaround aims to break the deadlock situation
+ * when after long transfer over uart in hardware flow
+ * control, uart interrupt registers cannot be cleared.
+ * Hence uart transfer gets blocked.
+ *
+ * It is seen that during such deadlock condition ICR
+ * don't get cleared even on multiple write. This leads
+ * pass_counter to decrease and finally reach zero. This
+ * can be taken as trigger point to run pl011_lockup_wa().
+ *
+ */
+static void pl011_lockup_wa(unsigned long data)
+{
+ struct uart_amba_port *uap = amba_ports[0];
+ void __iomem *base = uap->port.membase;
+ struct circ_buf *xmit = &uap->port.state->xmit;
+ struct tty_struct *tty = uap->port.state->port.tty;
+ int buf_empty_retries = 200;
+ int loop;
+
+ /* Stop HCI layer from submitting data for tx */
+ tty->hw_stopped = 1;
+ while (!uart_circ_empty(xmit)) {
+ if (buf_empty_retries-- == 0)
+ break;
+ udelay(100);
+ }
+
+ /* Backup registers */
+ for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
+ uart_wa_regdata[loop] = readl(base + uart_wa_reg[loop]);
+
+ /* Disable UART so that FIFO data is flushed out */
+ writew(0x00, uap->port.membase + UART011_CR);
+
+ /* Soft reset UART module */
+ if (uap->port.dev->platform_data) {
+ struct amba_pl011_data *plat;
+
+ plat = uap->port.dev->platform_data;
+ if (plat->reset)
+ plat->reset();
+ }
+
+ /* Restore registers */
+ for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
+ writew(uart_wa_regdata[loop] ,
+ uap->port.membase + uart_wa_reg[loop]);
+
+ /* Initialise the old status of the modem signals */
+ uap->old_status = readw(uap->port.membase + UART01x_FR) &
+ UART01x_FR_MODEM_ANY;
+
+ if (readl(base + UART011_MIS) & 0x2)
+ printk(KERN_EMERG "UART_BT_WA: ***FAILED***\n");
+
+ /* Start Tx/Rx */
+ tty->hw_stopped = 0;
+}
+
static void pl011_stop_tx(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -1158,8 +1250,11 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
if (status & UART011_TXIS)
pl011_tx_chars(uap);

- if (pass_counter-- == 0)
+ if (pass_counter-- == 0) {
+ if (uap->interrupt_may_hang)
+ tasklet_schedule(&pl011_lockup_tlet);
break;
+ }

status = readw(uap->port.membase + UART011_MIS);
} while (status != 0);
@@ -1339,6 +1434,14 @@ static int pl011_startup(struct uart_port *port)
writew(uap->im, uap->port.membase + UART011_IMSC);
spin_unlock_irq(&uap->port.lock);

+ if (uap->port.dev->platform_data) {
+ struct amba_pl011_data *plat;
+
+ plat = uap->port.dev->platform_data;
+ if (plat->init)
+ plat->init();
+ }
+
return 0;

clk_dis:
@@ -1394,6 +1497,15 @@ static void pl011_shutdown(struct uart_port *port)
* Shut down the clock producer
*/
clk_disable(uap->clk);
+
+ if (uap->port.dev->platform_data) {
+ struct amba_pl011_data *plat;
+
+ plat = uap->port.dev->platform_data;
+ if (plat->exit)
+ plat->exit();
+ }
+
}

static void
@@ -1700,6 +1812,14 @@ static int __init pl011_console_setup(struct console *co, char *options)
if (!uap)
return -ENODEV;

+ if (uap->port.dev->platform_data) {
+ struct amba_pl011_data *plat;
+
+ plat = uap->port.dev->platform_data;
+ if (plat->init)
+ plat->init();
+ }
+
uap->port.uartclk = clk_get_rate(uap->clk);

if (options)
@@ -1774,6 +1894,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
uap->lcrh_rx = vendor->lcrh_rx;
uap->lcrh_tx = vendor->lcrh_tx;
uap->fifosize = vendor->fifosize;
+ uap->interrupt_may_hang = vendor->interrupt_may_hang;
uap->port.dev = &dev->dev;
uap->port.mapbase = dev->res.start;
uap->port.membase = base;
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h
index 5479fdc..4f69fb8 100644
--- a/include/linux/amba/serial.h
+++ b/include/linux/amba/serial.h
@@ -201,6 +201,9 @@ struct amba_pl011_data {
bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
void *dma_rx_param;
void *dma_tx_param;
+ void (*init) (void);
+ void (*exit) (void);
+ void (*reset) (void);
};
#endif

--
1.7.2.dirty

2011-05-17 05:23:27

by Shreshtha Kumar SAHU

[permalink] [raw]
Subject: [PATCHv2 2/2] amba pl011: platform data for reg lockup and glitch

From: Shreshtha Kumar Sahu <[email protected]>

This patch provides platform data for following
- uart reset function to assist uart register lockup workaround

- init/exit function to fix glitch in the tx pin in tty_open
when tty port0 is opened a glitch is seen in the tx line
of uart0. This happens in pl011_startup() when tx fifo
interrupt is provoked into asserting.
Now uart0 pins are enabled (alt function) only when init
is complete and turned back to gpio when closed.

Signed-off-by: Shreshtha Kumar Sahu <[email protected]>
---
changes in v2:
corrected function name in commit message
added missing header file include

arch/arm/mach-ux500/board-mop500-pins.c | 16 +++++++--
arch/arm/mach-ux500/board-mop500.c | 54 +++++++++++++++++++++++++++++++
2 files changed, 66 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c
index fd4cf1c..ceab640 100644
--- a/arch/arm/mach-ux500/board-mop500-pins.c
+++ b/arch/arm/mach-ux500/board-mop500-pins.c
@@ -110,10 +110,18 @@ static pin_cfg_t mop500_pins_common[] = {
GPIO168_KP_O0,

/* UART */
- GPIO0_U0_CTSn | PIN_INPUT_PULLUP,
- GPIO1_U0_RTSn | PIN_OUTPUT_HIGH,
- GPIO2_U0_RXD | PIN_INPUT_PULLUP,
- GPIO3_U0_TXD | PIN_OUTPUT_HIGH,
+ /* uart-0 pins gpio configuration should be
+ * kept intact to prevent glitch in tx line
+ * when tty dev is opened. Later these pins
+ * are configured to uart mop500_pins_uart0
+ *
+ * It will be replaced with uart configuration
+ * once the issue is solved.
+ */
+ GPIO0_GPIO | PIN_INPUT_PULLUP,
+ GPIO1_GPIO | PIN_OUTPUT_HIGH,
+ GPIO2_GPIO | PIN_INPUT_PULLUP,
+ GPIO3_GPIO | PIN_OUTPUT_LOW,

GPIO29_U2_RXD | PIN_INPUT_PULLUP,
GPIO30_U2_TXD | PIN_OUTPUT_HIGH,
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index 6e1907fa..97b2577 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -27,18 +27,21 @@
#include <linux/leds-lp5521.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
+#include <linux/delay.h>

#include <asm/mach-types.h>
#include <asm/mach/arch.h>

#include <plat/i2c.h>
#include <plat/ste_dma40.h>
+#include <plat/pincfg.h>

#include <mach/hardware.h>
#include <mach/setup.h>
#include <mach/devices.h>
#include <mach/irqs.h>

+#include "pins-db8500.h"
#include "ste-dma40-db8500.h"
#include "devices-db8500.h"
#include "board-mop500.h"
@@ -391,12 +394,63 @@ static struct stedma40_chan_cfg uart2_dma_cfg_tx = {
};
#endif

+
+static pin_cfg_t mop500_pins_uart0[] = {
+ GPIO0_U0_CTSn | PIN_INPUT_PULLUP,
+ GPIO1_U0_RTSn | PIN_OUTPUT_HIGH,
+ GPIO2_U0_RXD | PIN_INPUT_PULLUP,
+ GPIO3_U0_TXD | PIN_OUTPUT_HIGH,
+};
+
+#define PRCC_K_SOFTRST_SET 0x18
+#define PRCC_K_SOFTRST_CLEAR 0x1C
+static void ux500_uart0_reset(void)
+{
+ void __iomem *prcc_rst_set, *prcc_rst_clr;
+
+ prcc_rst_set = (void __iomem *)IO_ADDRESS(U8500_CLKRST1_BASE +
+ PRCC_K_SOFTRST_SET);
+ prcc_rst_clr = (void __iomem *)IO_ADDRESS(U8500_CLKRST1_BASE +
+ PRCC_K_SOFTRST_CLEAR);
+
+ /* Activate soft reset PRCC_K_SOFTRST_CLEAR */
+ writel((readl(prcc_rst_clr) | 0x1), prcc_rst_clr);
+ udelay(1);
+
+ /* Release soft reset PRCC_K_SOFTRST_SET */
+ writel((readl(prcc_rst_set) | 0x1), prcc_rst_set);
+ udelay(1);
+}
+
+static void ux500_uart0_init(void)
+{
+ int ret;
+
+ ret = nmk_config_pins(mop500_pins_uart0,
+ ARRAY_SIZE(mop500_pins_uart0));
+ if (ret < 0)
+ pr_err("pl011: uart pins_enable failed\n");
+}
+
+static void ux500_uart0_exit(void)
+{
+ int ret;
+
+ ret = nmk_config_pins_sleep(mop500_pins_uart0,
+ ARRAY_SIZE(mop500_pins_uart0));
+ if (ret < 0)
+ pr_err("pl011: uart pins_disable failed\n");
+}
+
static struct amba_pl011_data uart0_plat = {
#ifdef CONFIG_STE_DMA40
.dma_filter = stedma40_filter,
.dma_rx_param = &uart0_dma_cfg_rx,
.dma_tx_param = &uart0_dma_cfg_tx,
#endif
+ .init = ux500_uart0_init,
+ .exit = ux500_uart0_exit,
+ .reset = ux500_uart0_reset,
};

static struct amba_pl011_data uart1_plat = {
--
1.7.2.dirty

2011-05-17 18:24:08

by Greg KH

[permalink] [raw]
Subject: Re: [PATCHv2 1/2] amba pl011: workaround for uart registers lockup

On Tue, May 17, 2011 at 10:50:17AM +0530, Shreshtha Kumar SAHU wrote:
> From: Shreshtha Kumar Sahu <[email protected]>
>
> This workaround aims to break the deadlock situation
> which raises during continuous transfer of data for long
> duration over uart with hardware flow control. It is
> observed that CTS interrupt cannot be cleared in uart
> interrupt register (ICR). Hence further transfer over
> uart gets blocked.
>
> It is seen that during such deadlock condition ICR
> don't get cleared even on multiple write. This leads
> pass_counter to decrease and finally reach zero. This
> can be taken as trigger point to run this UART_BT_WA.
>
> Workaround backups the register configuration, does soft
> reset of UART using BIT-0 of PRCC_K_SOFTRST_SET/CLEAR
> registers and restores the registers.
>
> This patch also provides support for uart init and exit
> function calls if present.

Why? You don't use these callbacks in this driver, so why add them?

confused,

greg k-h

2011-05-17 18:30:38

by Russell King

[permalink] [raw]
Subject: Re: [PATCHv2 1/2] amba pl011: workaround for uart registers lockup

On Tue, May 17, 2011 at 11:23:56AM -0700, Greg KH wrote:
> Why? You don't use these callbacks in this driver, so why add them?

Did you look at the second patch?

--
Russell King
Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/
maintainer of:

2011-05-17 18:41:38

by Greg KH

[permalink] [raw]
Subject: Re: [PATCHv2 1/2] amba pl011: workaround for uart registers lockup

On Tue, May 17, 2011 at 07:30:15PM +0100, Russell King wrote:
> On Tue, May 17, 2011 at 11:23:56AM -0700, Greg KH wrote:
> > Why? You don't use these callbacks in this driver, so why add them?
>
> Did you look at the second patch?

The second patch was not sent to me, so I couldn't have seen it :(

thanks,

greg k-h

2011-05-17 18:45:48

by Russell King

[permalink] [raw]
Subject: Re: [PATCHv2 1/2] amba pl011: workaround for uart registers lockup

On Tue, May 17, 2011 at 11:40:19AM -0700, Greg KH wrote:
> On Tue, May 17, 2011 at 07:30:15PM +0100, Russell King wrote:
> > On Tue, May 17, 2011 at 11:23:56AM -0700, Greg KH wrote:
> > > Why? You don't use these callbacks in this driver, so why add them?
> >
> > Did you look at the second patch?
>
> The second patch was not sent to me, so I couldn't have seen it :(

Ok, I've just forwarded you the second patch.

--
Russell King
Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/
maintainer of:

2011-05-17 18:54:03

by Greg KH

[permalink] [raw]
Subject: Re: [PATCHv2 1/2] amba pl011: workaround for uart registers lockup

On Tue, May 17, 2011 at 11:23:56AM -0700, Greg KH wrote:
> On Tue, May 17, 2011 at 10:50:17AM +0530, Shreshtha Kumar SAHU wrote:
> > From: Shreshtha Kumar Sahu <[email protected]>
> >
> > This workaround aims to break the deadlock situation
> > which raises during continuous transfer of data for long
> > duration over uart with hardware flow control. It is
> > observed that CTS interrupt cannot be cleared in uart
> > interrupt register (ICR). Hence further transfer over
> > uart gets blocked.
> >
> > It is seen that during such deadlock condition ICR
> > don't get cleared even on multiple write. This leads
> > pass_counter to decrease and finally reach zero. This
> > can be taken as trigger point to run this UART_BT_WA.
> >
> > Workaround backups the register configuration, does soft
> > reset of UART using BIT-0 of PRCC_K_SOFTRST_SET/CLEAR
> > registers and restores the registers.
> >
> > This patch also provides support for uart init and exit
> > function calls if present.
>
> Why? You don't use these callbacks in this driver, so why add them?

Ok, I see them in the 2/2 patch now, thanks.

Do you still want me to take this patch through the serial tree, or will
both be going through some ARM tree?

greg k-h

2011-06-09 19:46:43

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCHv2 1/2] amba pl011: workaround for uart registers lockup

On Tue, May 17, 2011 at 8:51 PM, Greg KH <[email protected]> wrote:

> Do you still want me to take this patch through the serial tree, or will
> both be going through some ARM tree?

Hm these two patches appear to be stuck in limbo, missing the
merge window and all.

Which is sad, because they fix real issues to us.

How do we proceed?

Thanks,
Linus Walleij

2011-06-09 20:18:51

by Greg KH

[permalink] [raw]
Subject: Re: [PATCHv2 1/2] amba pl011: workaround for uart registers lockup

On Thu, Jun 09, 2011 at 09:46:26PM +0200, Linus Walleij wrote:
> On Tue, May 17, 2011 at 8:51 PM, Greg KH <[email protected]> wrote:
>
> > Do you still want me to take this patch through the serial tree, or will
> > both be going through some ARM tree?
>
> Hm these two patches appear to be stuck in limbo, missing the
> merge window and all.
>
> Which is sad, because they fix real issues to us.
>
> How do we proceed?

Resend them and I'll take them.

thanks,

greg k-h