From 24bb1e7066cf302f71b50140fce7b5b37cdcbe2b Mon Sep 17 00:00:00 2001 From: Bin Yang Date: Thu, 19 Apr 2012 18:34:05 +0800 Subject: [PATCH] add HSU RX timeout workarround for CTP BZ: 31975 HSU RX timeout interrupt is lost for silicon issue. Need this workarround to recovery the interrupt. Change-Id: Ie38ac427519e04d5043cebc06873e4d429b8acaf Signed-off-by: Bin Yang Reviewed-on: http://android.intel.com:8080/44029 Reviewed-by: Kuppuswamy, Sathyanarayanan Reviewed-by: Wang, Yiyang Reviewed-by: Du, Alek Tested-by: Wang, Zhifeng Reviewed-by: buildbot Tested-by: buildbot --- arch/x86/include/asm/intel_mid_hsu.h | 1 + arch/x86/platform/intel-mid/mfld-hsu.c | 10 ++++++++++ drivers/tty/serial/mfd.c | 25 ++++++++++++++++++++----- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/intel_mid_hsu.h b/arch/x86/include/asm/intel_mid_hsu.h index 267689f..d2fdbd4 100644 --- a/arch/x86/include/asm/intel_mid_hsu.h +++ b/arch/x86/include/asm/intel_mid_hsu.h @@ -20,6 +20,7 @@ struct mfld_hsu_info { extern struct mfld_hsu_info *platform_hsu_info; extern unsigned char hsu_dma_enable; +extern int hsu_rx_wa; void intel_mid_hsu_suspend(int port); void intel_mid_hsu_resume(int port); void intel_mid_hsu_switch(int port); diff --git a/arch/x86/platform/intel-mid/mfld-hsu.c b/arch/x86/platform/intel-mid/mfld-hsu.c index 597e5a7..fcc3450 100644 --- a/arch/x86/platform/intel-mid/mfld-hsu.c +++ b/arch/x86/platform/intel-mid/mfld-hsu.c @@ -25,6 +25,16 @@ int __init setup_hsu_dma_enable_flag(char *p) } early_param("hsu_dma", setup_hsu_dma_enable_flag); +int hsu_rx_wa; +EXPORT_SYMBOL_GPL(hsu_rx_wa); + +int __init setup_hsu_rx_workarround_flag(char *p) +{ + hsu_rx_wa = 1; + return 0; +} +early_param("hsu_rx_wa", setup_hsu_rx_workarround_flag); + static struct mfld_hsu_info default_hsu_info[] = { [0] = { .id = 0, diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c index f619469..56796cc 100644 --- a/drivers/tty/serial/mfd.c +++ b/drivers/tty/serial/mfd.c @@ -57,7 +57,7 @@ #define mfd_readl(obj, offset) readl(obj->reg + offset) #define mfd_writel(obj, offset, val) writel(val, obj->reg + offset) -#define HSU_DMA_TIMEOUT_CHECK_FREQ (HZ/10) +#define HSU_DMA_TIMEOUT_CHECK_FREQ (HZ/100) struct hsu_dma_buffer { u8 *buf; @@ -200,7 +200,15 @@ module_param(hsu_low_latency, uint, S_IRUGO); */ static inline int dmarx_need_timer(void) { - return (boot_cpu_data.x86_model == 0x27 && boot_cpu_data.x86_mask == 0); + return hsu_rx_wa || + (boot_cpu_data.x86_model == 0x27 && + boot_cpu_data.x86_mask == 0); +} + +static inline void runtime_suspend_delay(struct uart_hsu_port *up) +{ + pm_runtime_get(up->dev); + pm_runtime_put(up->dev); } static inline unsigned int serial_in_irq(struct uart_hsu_port *up, int offset) @@ -517,8 +525,10 @@ void hsu_dma_start_rx_chan(struct uart_hsu_port *up, chan_writel(rxc, HSU_CH_CR, 0x3); up->dma_rx_on = 1; - if (dmarx_need_timer()) + if (dmarx_need_timer()) { mod_timer(&rxc->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ); + runtime_suspend_delay(up); + } } /* Protected by spin_lock_irqsave(port->lock) */ @@ -598,6 +608,7 @@ static void hsu_dma_rx_tasklet(unsigned long data) chan->rx_timer.expires = jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ; add_timer(&chan->rx_timer); + runtime_suspend_delay(up); } /* If function is called from tasklet context, pm_runtime @@ -642,8 +653,10 @@ void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts) return; } - if (dmarx_need_timer()) + if (dmarx_need_timer()) { del_timer(&chan->rx_timer); + runtime_suspend_delay(up); + } dma_sync_single_for_cpu(port->dev, dbuf->dma_addr, dbuf->dma_size, DMA_FROM_DEVICE); @@ -1708,9 +1721,11 @@ static void hsu_dma_rx_timeout(unsigned long data) count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr; if (!count) { - if (dmarx_need_timer()) + if (dmarx_need_timer()) { mod_timer(&chan->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ); + runtime_suspend_delay(up); + } goto exit; } -- 2.7.4