From patchwork Fri Nov 19 01:54:55 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nishanth Menon X-Patchwork-Id: 338081 X-Patchwork-Delegate: khilman@deeprootsystems.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id oAJ1tCVi025169 for ; Fri, 19 Nov 2010 01:55:36 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758428Ab0KSBzP (ORCPT ); Thu, 18 Nov 2010 20:55:15 -0500 Received: from comal.ext.ti.com ([198.47.26.152]:51918 "EHLO comal.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756732Ab0KSBzD (ORCPT ); Thu, 18 Nov 2010 20:55:03 -0500 Received: from dlep36.itg.ti.com ([157.170.170.91]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id oAJ1t1ta006770 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Thu, 18 Nov 2010 19:55:01 -0600 Received: from legion.dal.design.ti.com (localhost [127.0.0.1]) by dlep36.itg.ti.com (8.13.8/8.13.8) with ESMTP id oAJ1t1g5006570; Thu, 18 Nov 2010 19:55:01 -0600 (CST) Received: from senorita (senorita.am.dhcp.ti.com [128.247.74.250]) by legion.dal.design.ti.com (8.11.7p1+Sun/8.11.7) with ESMTP id oAJ1t0f12113; Thu, 18 Nov 2010 19:55:00 -0600 (CST) Received: by senorita (Postfix, from userid 1000) id 2EFB3C2B2; Thu, 18 Nov 2010 19:54:58 -0600 (CST) From: Nishanth Menon To: linux-omap Cc: Kevin , Jean Pihet , Vishwanath Sripathy , Tony Subject: [PATCH 10/13] OMAP3: PM: Errata i582: per domain reset issue: uart Date: Thu, 18 Nov 2010 19:54:55 -0600 Message-Id: <1290131698-6194-11-git-send-email-nm@ti.com> X-Mailer: git-send-email 1.6.3.3 In-Reply-To: <1290131698-6194-1-git-send-email-nm@ti.com> References: <1290131698-6194-1-git-send-email-nm@ti.com> Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Fri, 19 Nov 2010 01:55:36 +0000 (UTC) diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index c7e2db0..218d0b0 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -84,6 +84,10 @@ static struct powerdomain *cam_pwrdm; static int secure_ram_save_status; static int secure_ram_saved; +#define PER_WAKEUP_ERRATA_i582 (1 << 0) +static u16 pm34xx_errata; +#define IS_PM34XX_ERRATA(id) (pm34xx_errata & (id)) + static inline void omap3_per_save_context(void) { omap_gpio_save_context(); @@ -371,7 +375,8 @@ void omap_sram_idle(void) int mpu_next_state = PWRDM_POWER_ON; int per_next_state = PWRDM_POWER_ON; int core_next_state = PWRDM_POWER_ON; - int core_prev_state, per_prev_state; + int core_prev_state = PWRDM_POWER_ON; + int per_prev_state = PWRDM_POWER_ON; u32 sdrc_pwr = 0; if (!_omap_sram_idle) @@ -496,6 +501,23 @@ void omap_sram_idle(void) omap3_per_restore_context(); omap_uart_resume_idle(2); omap_uart_resume_idle(3); + if (IS_PM34XX_ERRATA(PER_WAKEUP_ERRATA_i582) && + omap_uart_check_per_uarts_used() && + (core_prev_state == PWRDM_POWER_ON) && + (per_prev_state == PWRDM_POWER_OFF)) { + /* + * We dont seem to have a real recovery other than reset + * Errata i582:Alternative available here is to do a + * reboot OR go to per off/core off, we will just print + * and cause uart to be in an unstable state and + * continue on till we hit the next off transition. + * Reboot of the device due to this corner case is + * undesirable. + */ + if (omap_uart_per_errata()) + pr_err("%s: PER UART hit with Errata i582 " + "Corner case.\n", __func__); + } } /* Disable IO-PAD and IO-CHAIN wakeup */ @@ -1021,15 +1043,27 @@ void omap_push_sram_idle(void) save_secure_ram_context_sz); } +static void pm_errata_configure(void) +{ + if (cpu_is_omap34xx()) { + pm34xx_errata |= PER_WAKEUP_ERRATA_i582; + if (cpu_is_omap3630() && (omap_rev() > OMAP3630_REV_ES1_1)) + pm34xx_errata &= ~PER_WAKEUP_ERRATA_i582; + } +} + static int __init omap3_pm_init(void) { struct power_state *pwrst, *tmp; struct clockdomain *neon_clkdm, *per_clkdm, *mpu_clkdm, *core_clkdm; + struct clockdomain *wkup_clkdm; int ret; if (!cpu_is_omap34xx()) return -ENODEV; + pm_errata_configure(); + printk(KERN_ERR "Power Management for TI OMAP3.\n"); /* XXX prcm_setup_regs needs to be before enabling hw @@ -1067,6 +1101,7 @@ static int __init omap3_pm_init(void) neon_clkdm = clkdm_lookup("neon_clkdm"); mpu_clkdm = clkdm_lookup("mpu_clkdm"); per_clkdm = clkdm_lookup("per_clkdm"); + wkup_clkdm = clkdm_lookup("wkup_clkdm"); core_clkdm = clkdm_lookup("core_clkdm"); omap_push_sram_idle(); @@ -1077,6 +1112,10 @@ static int __init omap3_pm_init(void) pm_idle = omap3_pm_idle; omap3_idle_init(); + /* Allow per to wakeup the system if errata is applicable */ + if (IS_PM34XX_ERRATA(PER_WAKEUP_ERRATA_i582) && cpu_is_omap34xx()) + clkdm_add_wkdep(per_clkdm, wkup_clkdm); + clkdm_add_wkdep(neon_clkdm, mpu_clkdm); omap3_save_scratchpad_contents(); diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index becf0e3..43c2ec4 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -273,6 +273,86 @@ static void omap_uart_restore_context(struct omap_uart_state *uart) /* UART 16x mode */ serial_write_reg(uart, UART_OMAP_MDR1, 0x00); } + +static inline int _is_per_uart(struct omap_uart_state *uart) +{ + if (cpu_is_omap34xx() && (uart->num == 2 || uart->num == 3)) + return 1; + return 0; +} + +int omap_uart_check_per_uarts_used(void) +{ + struct omap_uart_state *uart; + + list_for_each_entry(uart, &uart_list, node) { + if (_is_per_uart(uart)) + return 1; + } + return 0; +} + +/* + * Errata i582 affects PER UARTS..Loop back test is done to + * check the UART state when the corner case is encountered + */ +static int omap_uart_loopback_test(struct omap_uart_state *uart) +{ + u8 loopbk_rhr = 0; + + omap_uart_save_context(uart); + serial_write_reg(uart, UART_OMAP_MDR1, 0x7); + serial_write_reg(uart, UART_LCR, 0xBF); /* Config B mode */ + serial_write_reg(uart, UART_DLL, uart->dll); + serial_write_reg(uart, UART_DLM, uart->dlh); + serial_write_reg(uart, UART_LCR, 0x0); /* Operational mode */ + /* configure uart3 in UART mode */ + serial_write_reg(uart, UART_OMAP_MDR1, 0x00); /* UART 16x mode */ + serial_write_reg(uart, UART_LCR, 0x80); + /* Enable internal loop back mode by setting MCR_REG[4].LOOPBACK_EN */ + serial_write_reg(uart, UART_MCR, 0x10); + + /* write to THR,read RHR and compare */ + /* Tx output is internally looped back to Rx input in loop back mode */ + serial_write_reg(uart, UART_LCR_DLAB, 0x00); + /* Enables write to THR and read from RHR */ + serial_write_reg(uart, UART_TX, 0xCC); /* writing data to THR */ + /* reading data from RHR */ + loopbk_rhr = (serial_read_reg(uart, UART_RX) & 0xFF); + if (loopbk_rhr == 0xCC) { + /* compare passes,try comparing with different data */ + serial_write_reg(uart, UART_TX, 0x69); + loopbk_rhr = (serial_read_reg(uart, UART_RX) & 0xFF); + if (loopbk_rhr == 0x69) { + /* compare passes,reset UART3 and re-configure module */ + omap_uart_reset(uart); + omap_uart_restore_context(uart); + return 0; + } + } else { /* requires warm reset */ + return -ENODEV; + } + return 0; +} + +int omap_uart_per_errata(void) +{ + struct omap_uart_state *uart; + + /* For all initialised UART modules that are in PER domain + * do loopback test + */ + list_for_each_entry(uart, &uart_list, node) { + if (_is_per_uart(uart)) { + if (omap_uart_loopback_test(uart)) + return -ENODEV; + else + return 0; + } + } + return 0; +} + #else static inline void omap_uart_save_context(struct omap_uart_state *uart) {} static inline void omap_uart_restore_context(struct omap_uart_state *uart) {} diff --git a/arch/arm/plat-omap/include/plat/serial.h b/arch/arm/plat-omap/include/plat/serial.h index 19145f5..81169b2 100644 --- a/arch/arm/plat-omap/include/plat/serial.h +++ b/arch/arm/plat-omap/include/plat/serial.h @@ -102,6 +102,10 @@ extern void omap_uart_prepare_suspend(void); extern void omap_uart_prepare_idle(int num); extern void omap_uart_resume_idle(int num); extern void omap_uart_enable_irqs(int enable); +#ifdef CONFIG_PM +extern int omap_uart_per_errata(void); +extern int omap_uart_check_per_uarts_used(void); +#endif #endif #endif