Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 281905
b: refs/heads/master
c: 9473474
h: refs/heads/master
i:
  281903: 5c34195
v: v3
  • Loading branch information
Govindraj.R authored and Kevin Hilman committed Dec 15, 2011
1 parent eafe8fb commit 942b69d
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 75 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ec3bebc6ec64aac23500e6b8ef5c0aaaeda735cf
refs/heads/master: 94734749af794c080f6af6ac3ce8c1c13ee2dbbd
101 changes: 31 additions & 70 deletions trunk/arch/arm/mach-omap2/serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@
#include "control.h"
#include "mux.h"

#define UART_ERRATA_i202_MDR1_ACCESS (0x1 << 1)

/*
* NOTE: By default the serial timeout is disabled as it causes lost characters
* over the serial ports. This means that the UART clocks will stay on until
Expand All @@ -61,59 +59,17 @@ struct omap_uart_state {
void __iomem *wk_st;
void __iomem *wk_en;
u32 wk_mask;
u32 dma_enabled;

int clocked;

struct list_head node;
struct omap_hwmod *oh;
struct platform_device *pdev;

u32 errata;
};

static LIST_HEAD(uart_list);
static u8 num_uarts;

#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3)

/*
* Work Around for Errata i202 (3430 - 1.12, 3630 - 1.6)
* The access to uart register after MDR1 Access
* causes UART to corrupt data.
*
* Need a delay =
* 5 L4 clock cycles + 5 UART functional clock cycle (@48MHz = ~0.2uS)
* give 10 times as much
*/
static void omap_uart_mdr1_errataset(struct omap_uart_state *uart, u8 mdr1_val,
u8 fcr_val)
{
u8 timeout = 255;

serial_write_reg(uart, UART_OMAP_MDR1, mdr1_val);
udelay(2);
serial_write_reg(uart, UART_FCR, fcr_val | UART_FCR_CLEAR_XMIT |
UART_FCR_CLEAR_RCVR);
/*
* Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and
* TX_FIFO_E bit is 1.
*/
while (UART_LSR_THRE != (serial_read_reg(uart, UART_LSR) &
(UART_LSR_THRE | UART_LSR_DR))) {
timeout--;
if (!timeout) {
/* Should *never* happen. we warn and carry on */
dev_crit(&uart->pdev->dev, "Errata i202: timedout %x\n",
serial_read_reg(uart, UART_LSR));
break;
}
udelay(1);
}
}

#endif /* CONFIG_PM && CONFIG_ARCH_OMAP3 */

static inline void omap_uart_enable_clocks(struct omap_uart_state *uart)
{
if (uart->clocked)
Expand Down Expand Up @@ -156,27 +112,6 @@ static void omap_uart_disable_wakeup(struct omap_uart_state *uart)
}
}

static void omap_uart_smart_idle_enable(struct omap_uart_state *uart,
int enable)
{
u8 idlemode;

if (enable) {
/**
* Errata 2.15: [UART]:Cannot Acknowledge Idle Requests
* in Smartidle Mode When Configured for DMA Operations.
*/
if (uart->dma_enabled)
idlemode = HWMOD_IDLEMODE_FORCE;
else
idlemode = HWMOD_IDLEMODE_SMART;
} else {
idlemode = HWMOD_IDLEMODE_NO;
}

omap_hwmod_set_slave_idlemode(uart->oh, idlemode);
}

static void omap_uart_block_sleep(struct omap_uart_state *uart)
{
omap_uart_enable_clocks(uart);
Expand Down Expand Up @@ -267,7 +202,28 @@ static void omap_uart_idle_init(struct omap_uart_state *uart)
}
}

/*
* Errata i291: [UART]:Cannot Acknowledge Idle Requests
* in Smartidle Mode When Configured for DMA Operations.
* WA: configure uart in force idle mode.
*/
static void omap_uart_set_noidle(struct platform_device *pdev)
{
struct omap_device *od = to_omap_device(pdev);

omap_hwmod_set_slave_idlemode(od->hwmods[0], HWMOD_IDLEMODE_NO);
}

static void omap_uart_set_forceidle(struct platform_device *pdev)
{
struct omap_device *od = to_omap_device(pdev);

omap_hwmod_set_slave_idlemode(od->hwmods[0], HWMOD_IDLEMODE_FORCE);
}

#else
static void omap_uart_set_noidle(struct platform_device *pdev) {}
static void omap_uart_set_forceidle(struct platform_device *pdev) {}
static void omap_uart_block_sleep(struct omap_uart_state *uart)
{
/* Needed to enable UART clocks when built without CONFIG_PM */
Expand Down Expand Up @@ -473,13 +429,22 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
break;

oh = uart->oh;
uart->dma_enabled = 0;
name = DRIVER_NAME;

omap_up.dma_enabled = uart->dma_enabled;
omap_up.uartclk = OMAP24XX_BASE_BAUD * 16;
omap_up.flags = UPF_BOOT_AUTOCONF;
omap_up.get_context_loss_count = omap_pm_get_dev_context_loss_count;
omap_up.set_forceidle = omap_uart_set_forceidle;
omap_up.set_noidle = omap_uart_set_noidle;

/* Enable the MDR1 Errata i202 for OMAP2430/3xxx/44xx */
if (!cpu_is_omap2420() && !cpu_is_ti816x())
omap_up.errata |= UART_ERRATA_i202_MDR1_ACCESS;

/* Enable DMA Mode Force Idle Errata i291 for omap34xx/3630 */
if (cpu_is_omap34xx() || cpu_is_omap3630())
omap_up.errata |= UART_ERRATA_i291_DMA_FORCEIDLE;

pdata = &omap_up;
pdata_size = sizeof(struct omap_uart_port_info);
Expand Down Expand Up @@ -519,10 +484,6 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)
if (((cpu_is_omap34xx() || cpu_is_omap44xx()) && bdata->pads) ||
(pdata->wk_en && pdata->wk_mask))
device_init_wakeup(&pdev->dev, true);

/* Enable the MDR1 errata for OMAP3 */
if (cpu_is_omap34xx() && !(cpu_is_ti81xx() || cpu_is_am33xx()))
uart->errata |= UART_ERRATA_i202_MDR1_ACCESS;
}

/**
Expand Down
7 changes: 7 additions & 0 deletions trunk/arch/arm/plat-omap/include/plat/omap-serial.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,18 @@

#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA

#define UART_ERRATA_i202_MDR1_ACCESS BIT(0)
#define UART_ERRATA_i291_DMA_FORCEIDLE BIT(1)

struct omap_uart_port_info {
bool dma_enabled; /* To specify DMA Mode */
unsigned int uartclk; /* UART clock rate */
upf_t flags; /* UPF_* flags */
u32 errata;

int (*get_context_loss_count)(struct device *);
void (*set_forceidle)(struct platform_device *);
void (*set_noidle)(struct platform_device *);
};

struct uart_omap_dma {
Expand Down Expand Up @@ -117,6 +123,7 @@ struct uart_omap_port {
char name[20];
unsigned long port_activity;
u32 context_loss_cnt;
u32 errata;
};

#endif /* __OMAP_SERIAL_H__ */
68 changes: 64 additions & 4 deletions trunk/drivers/tty/serial/omap-serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
static void uart_tx_dma_callback(int lch, u16 ch_status, void *data);
static void serial_omap_rx_timeout(unsigned long uart_no);
static int serial_omap_start_rxdma(struct uart_omap_port *up);
static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1);

static inline unsigned int serial_in(struct uart_omap_port *up, int offset)
{
Expand Down Expand Up @@ -808,7 +809,11 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,

/* Protocol, Baud Rate, and Interrupt Settings */

serial_out(up, UART_OMAP_MDR1, up->mdr1);
if (up->errata & UART_ERRATA_i202_MDR1_ACCESS)
serial_omap_mdr1_errataset(up, up->mdr1);
else
serial_out(up, UART_OMAP_MDR1, up->mdr1);

serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);

up->efr = serial_in(up, UART_EFR);
Expand All @@ -833,7 +838,10 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
else
up->mdr1 = UART_OMAP_MDR1_16X_MODE;

serial_out(up, UART_OMAP_MDR1, up->mdr1);
if (up->errata & UART_ERRATA_i202_MDR1_ACCESS)
serial_omap_mdr1_errataset(up, up->mdr1);
else
serial_out(up, UART_OMAP_MDR1, up->mdr1);

/* Hardware Flow Control Configuration */

Expand Down Expand Up @@ -1362,6 +1370,7 @@ static int serial_omap_probe(struct platform_device *pdev)
up->port.flags = omap_up_info->flags;
up->port.uartclk = omap_up_info->uartclk;
up->uart_dma.uart_base = mem->start;
up->errata = omap_up_info->errata;

if (omap_up_info->dma_enabled) {
up->uart_dma.uart_dma_tx = dma_tx->start;
Expand Down Expand Up @@ -1415,9 +1424,47 @@ static int serial_omap_remove(struct platform_device *dev)
return 0;
}

/*
* Work Around for Errata i202 (2430, 3430, 3630, 4430 and 4460)
* The access to uart register after MDR1 Access
* causes UART to corrupt data.
*
* Need a delay =
* 5 L4 clock cycles + 5 UART functional clock cycle (@48MHz = ~0.2uS)
* give 10 times as much
*/
static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1)
{
u8 timeout = 255;

serial_out(up, UART_OMAP_MDR1, mdr1);
udelay(2);
serial_out(up, UART_FCR, up->fcr | UART_FCR_CLEAR_XMIT |
UART_FCR_CLEAR_RCVR);
/*
* Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and
* TX_FIFO_E bit is 1.
*/
while (UART_LSR_THRE != (serial_in(up, UART_LSR) &
(UART_LSR_THRE | UART_LSR_DR))) {
timeout--;
if (!timeout) {
/* Should *never* happen. we warn and carry on */
dev_crit(&up->pdev->dev, "Errata i202: timedout %x\n",
serial_in(up, UART_LSR));
break;
}
udelay(1);
}
}

static void serial_omap_restore_context(struct uart_omap_port *up)
{
serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE);
if (up->errata & UART_ERRATA_i202_MDR1_ACCESS)
serial_omap_mdr1_errataset(up, UART_OMAP_MDR1_DISABLE);
else
serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE);

serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /* Config B mode */
serial_out(up, UART_EFR, UART_EFR_ECB);
serial_out(up, UART_LCR, 0x0); /* Operational mode */
Expand All @@ -1434,7 +1481,10 @@ static void serial_omap_restore_context(struct uart_omap_port *up)
serial_out(up, UART_OMAP_SCR, up->scr);
serial_out(up, UART_EFR, up->efr);
serial_out(up, UART_LCR, up->lcr);
serial_out(up, UART_OMAP_MDR1, up->mdr1);
if (up->errata & UART_ERRATA_i202_MDR1_ACCESS)
serial_omap_mdr1_errataset(up, up->mdr1);
else
serial_out(up, UART_OMAP_MDR1, up->mdr1);
}

#ifdef CONFIG_PM_RUNTIME
Expand All @@ -1449,6 +1499,11 @@ static int serial_omap_runtime_suspend(struct device *dev)
if (pdata->get_context_loss_count)
up->context_loss_cnt = pdata->get_context_loss_count(dev);

/* Errata i291 */
if (up->use_dma && pdata->set_forceidle &&
(up->errata & UART_ERRATA_i291_DMA_FORCEIDLE))
pdata->set_forceidle(up->pdev);

return 0;
}

Expand All @@ -1464,6 +1519,11 @@ static int serial_omap_runtime_resume(struct device *dev)
if (up->context_loss_cnt != loss_cnt)
serial_omap_restore_context(up);
}

/* Errata i291 */
if (up->use_dma && pdata->set_noidle &&
(up->errata & UART_ERRATA_i291_DMA_FORCEIDLE))
pdata->set_noidle(up->pdev);
}

return 0;
Expand Down

0 comments on commit 942b69d

Please sign in to comment.