From edd66078f5a0d7e60adc03ed6d6fc92d5a764352 Mon Sep 17 00:00:00 2001 From: Jay Cheng Date: Thu, 6 Jan 2011 00:16:18 -0500 Subject: [PATCH 1/6] usb: ehci: tegra: remove reschedule rh_timer Reschedule rh_timer may cause usb device resume fail, as rh_timer may be timeout and send USB_REQ_GET_STATUS SETUP control transfer by the time when the device is handling clear suspend feature, which in turn the device may drop clear suspend feature request. Actually on port resume case, the host driver don't need to reschedule rh_timer to check port status. The host driver will check port status right after suspend feature is cleared. Change-Id: I6205e97af49ed4349b6215b851f6b5f1394258d8 Signed-off-by: Jay Cheng --- drivers/usb/host/ehci-tegra.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 262bbb01228b..0e9b6458da84 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -151,11 +151,7 @@ static int tegra_ehci_hub_control( tegra_usb_phy_preresume(tegra->phy); - /* reschedule root hub polling during resume signaling */ ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25); - /* check the port again */ - mod_timer(&ehci_to_hcd(ehci)->rh_timer, - ehci->reset_done[wIndex-1]); temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); /* start resume signalling */ @@ -173,6 +169,8 @@ static int tegra_ehci_hub_control( if (handshake(ehci, status_reg, PORT_SUSPEND, 0, 2000)) pr_err("%s: timeout waiting for PORT_SUSPEND\n", __func__); + ehci->reset_done[wIndex-1] = 0; + tegra->port_resuming = 1; goto done; } From cfdeb3d801cfcdfbb17f7fd28bba00d4513c6558 Mon Sep 17 00:00:00 2001 From: Jay Cheng Date: Fri, 7 Jan 2011 02:03:46 -0500 Subject: [PATCH 2/6] ARM: tegra: usb_phy: continues driving FS-J during resume to prevent USB glitch. Change-Id: Iced668e33f986828d3a483b411055948b5b257e1 Signed-off-by: Jay Cheng --- arch/arm/mach-tegra/include/mach/usb_phy.h | 4 ++ arch/arm/mach-tegra/usb_phy.c | 47 ++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/arch/arm/mach-tegra/include/mach/usb_phy.h b/arch/arm/mach-tegra/include/mach/usb_phy.h index 8b4beae773a7..bb16019256ec 100644 --- a/arch/arm/mach-tegra/include/mach/usb_phy.h +++ b/arch/arm/mach-tegra/include/mach/usb_phy.h @@ -83,6 +83,10 @@ int tegra_usb_phy_preresume(struct tegra_usb_phy *phy); int tegra_usb_phy_postresume(struct tegra_usb_phy *phy); +int tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy); + +int tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy); + int tegra_usb_phy_close(struct tegra_usb_phy *phy); #endif //__MACH_USB_PHY_H diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c index f0d1ec803cfa..3dc3aed4c915 100644 --- a/arch/arm/mach-tegra/usb_phy.c +++ b/arch/arm/mach-tegra/usb_phy.c @@ -117,6 +117,12 @@ #define UTMIP_HS_DISCON_DISABLE (1 << 8) #define UTMIP_MISC_CFG0 0x824 +#define UTMIP_DPDM_OBSERVE (1 << 26) +#define UTMIP_DPDM_OBSERVE_SEL(x) (((x) & 0xf) << 27) +#define UTMIP_DPDM_OBSERVE_SEL_FS_J UTMIP_DPDM_OBSERVE_SEL(0xf) +#define UTMIP_DPDM_OBSERVE_SEL_FS_K UTMIP_DPDM_OBSERVE_SEL(0xe) +#define UTMIP_DPDM_OBSERVE_SEL_FS_SE1 UTMIP_DPDM_OBSERVE_SEL(0xd) +#define UTMIP_DPDM_OBSERVE_SEL_FS_SE0 UTMIP_DPDM_OBSERVE_SEL(0xc) #define UTMIP_SUSPEND_EXIT_ON_EDGE (1 << 22) #define UTMIP_MISC_CFG1 0x828 @@ -499,6 +505,33 @@ static void utmi_phy_postresume(struct tegra_usb_phy *phy) writel(val, base + UTMIP_TX_CFG0); } +static void utmi_phy_restore_start(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + val = readl(base + UTMIP_MISC_CFG0); + val |= UTMIP_DPDM_OBSERVE_SEL_FS_J; + writel(val, base + UTMIP_MISC_CFG0); + udelay(1); + + val = readl(base + UTMIP_MISC_CFG0); + val |= UTMIP_DPDM_OBSERVE; + writel(val, base + UTMIP_MISC_CFG0); + udelay(10); +} + +static void utmi_phy_restore_end(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + val = readl(base + UTMIP_MISC_CFG0); + val &= ~UTMIP_DPDM_OBSERVE; + writel(val, base + UTMIP_MISC_CFG0); + udelay(10); +} + static void ulpi_viewport_write(struct tegra_usb_phy *phy, u8 addr, u8 data) { unsigned long val; @@ -704,6 +737,20 @@ int tegra_usb_phy_postresume(struct tegra_usb_phy *phy) return 0; } +int tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy) +{ + if (phy->instance != 1) + utmi_phy_restore_start(phy); + return 0; +} + +int tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy) +{ + if (phy->instance != 1) + utmi_phy_restore_end(phy); + return 0; +} + int tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy) { if (phy->instance != 1) From e750de624e23fc8a8a6916c537394cbf3b38486c Mon Sep 17 00:00:00 2001 From: Jay Cheng Date: Fri, 7 Jan 2011 02:03:46 -0500 Subject: [PATCH 3/6] usb: ehci: tegra: continues driving FS-J during resume To prevent USB glitch. Also only program PTC bits when resume from LP0 Change-Id: Iced668e33f986828d3a483b411055948b5b257e1 Signed-off-by: Jay Cheng --- drivers/usb/host/ehci-tegra.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 0e9b6458da84..2341904808bc 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -253,6 +253,7 @@ static int tegra_usb_resume(struct usb_hcd *hcd) struct tegra_ehci_context *context = &tegra->context; struct ehci_regs __iomem *hw = tegra->ehci->regs; unsigned long val; + int lp0_resume = 0; set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); tegra_ehci_power_up(ehci_to_hcd(tegra->ehci)); @@ -264,6 +265,13 @@ static int tegra_usb_resume(struct usb_hcd *hcd) goto restart; } + tegra_ehci_phy_restore_start(tegra->phy); + + /* Check if the phy resume from LP0. When the phy resume from LP0 + * USB register will be reset. */ + if (!readl(&hw->async_next)) + lp0_resume = 1; + /* Restore register context */ writel(TEGRA_USB_USBMODE_HOST, &hw->reserved[19]); writel(context->otgsc, &hw->reserved[18]); @@ -278,17 +286,19 @@ static int tegra_usb_resume(struct usb_hcd *hcd) writel(val, &hw->port_status[0]); udelay(10); - /* Program the field PTC in PORTSC based on the saved speed mode */ - val = readl(&hw->port_status[0]); - val &= ~(TEGRA_USB_PORTSC1_PTC(~0)); - if (context->port_speed == TEGRA_USB_PHY_PORT_HIGH) - val |= TEGRA_USB_PORTSC1_PTC(5); - else if (context->port_speed == TEGRA_USB_PHY_PORT_SPEED_FULL) - val |= TEGRA_USB_PORTSC1_PTC(6); - else if (context->port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW) - val |= TEGRA_USB_PORTSC1_PTC(7); - writel(val, &hw->port_status[0]); - udelay(10); + if (lp0_resume) { + /* Program the field PTC in PORTSC based on the saved speed mode */ + val = readl(&hw->port_status[0]); + val &= ~(TEGRA_USB_PORTSC1_PTC(~0)); + if (context->port_speed == TEGRA_USB_PHY_PORT_HIGH) + val |= TEGRA_USB_PORTSC1_PTC(5); + else if (context->port_speed == TEGRA_USB_PHY_PORT_SPEED_FULL) + val |= TEGRA_USB_PORTSC1_PTC(6); + else if (context->port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW) + val |= TEGRA_USB_PORTSC1_PTC(7); + writel(val, &hw->port_status[0]); + udelay(10); + } /* Disable test mode by setting PTC field to NORMAL_OP */ val = readl(&hw->port_status[0]); @@ -330,9 +340,11 @@ static int tegra_usb_resume(struct usb_hcd *hcd) } } + tegra_ehci_phy_restore_end(tegra->phy); return 0; restart: + tegra_ehci_phy_restore_end(tegra->phy); tegra_ehci_restart(hcd); return 0; } From 178b6def88f0bc15a045ef7455cc7650d4deb859 Mon Sep 17 00:00:00 2001 From: Lowell Dennis Date: Tue, 14 Dec 2010 16:35:17 -0800 Subject: [PATCH 4/6] rtc: tps6586x: Fix error in RTC tick calculations In the TPS6586x PMU/PMIC RTC support code, when converting from seconds to ticks using a shift operator, the most significant bits were being lost due to seconds being a 32-bit value and ticks being a 64-bit value. A hard cast was added to avoid this loss. Reviewed-by: Lowell Dennis Tested-by: Lowell Dennis Reviewed-by: Jonathan Mayo Reviewed-by: Peter Zu Reviewed-by: Bharat Nihalani Signed-off-by: Robert Morell Signed-off-by: Colin Cross --- drivers/rtc/rtc-tps6586x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c index 9ab93cb9de0e..ca6138bbda4b 100644 --- a/drivers/rtc/rtc-tps6586x.c +++ b/drivers/rtc/rtc-tps6586x.c @@ -95,7 +95,7 @@ static int tps6586x_rtc_set_time(struct device *dev, struct rtc_time *tm) seconds -= rtc->epoch_start; - ticks = seconds << 10; + ticks = (unsigned long long)seconds << 10; buff[0] = (ticks >> 32) & 0xff; buff[1] = (ticks >> 24) & 0xff; buff[2] = (ticks >> 16) & 0xff; @@ -148,7 +148,7 @@ static int tps6586x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) } seconds -= rtc->epoch_start; - ticks = (seconds << 10) & 0xffffff; + ticks = (unsigned long long)seconds << 10; buff[0] = (ticks >> 16) & 0xff; buff[1] = (ticks >> 8) & 0xff; From aa49ac169f2f7f6a827f42118ec17355682b7a7f Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 5 Jan 2011 14:24:12 -0700 Subject: [PATCH 5/6] ARM: tegra: Prevent requeuing in-progress DMA requests If a request already in the queue is passed to tegra_dma_enqueue_req, tegra_dma_req.node->{next,prev} will end up pointing to itself instead of at tegra_dma_channel.list, which is the way a the end-of-list should be set up. When the DMA request completes and is list_del'd, the list head will still point at it, yet the node's next/prev will contain the list poison values. When the next DMA request completes, a kernel panic will occur when those poison values are dereferenced. This makes the DMA driver more robust in the face of buggy clients. Signed-off-by: Stephen Warren Signed-off-by: Colin Cross --- arch/arm/mach-tegra/dma.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c index 0ac303ebf84c..db94fcf58399 100644 --- a/arch/arm/mach-tegra/dma.c +++ b/arch/arm/mach-tegra/dma.c @@ -327,6 +327,7 @@ int tegra_dma_enqueue_req(struct tegra_dma_channel *ch, struct tegra_dma_req *req) { unsigned long irq_flags; + struct tegra_dma_req *_req; int start_dma = 0; if (req->size > TEGRA_DMA_MAX_TRANSFER_SIZE || @@ -337,6 +338,13 @@ int tegra_dma_enqueue_req(struct tegra_dma_channel *ch, spin_lock_irqsave(&ch->lock, irq_flags); + list_for_each_entry(_req, &ch->list, node) { + if (req == _req) { + spin_unlock_irqrestore(&ch->lock, irq_flags); + return -EEXIST; + } + } + req->bytes_transferred = 0; req->status = 0; /* STATUS_EMPTY just means the DMA hasn't processed the buf yet. */ From 962feda6df4542dfae908df64504c8e8046db1d4 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 4 Jan 2011 17:47:55 -0700 Subject: [PATCH 6/6] ARM: tegra: pll_a clock fixes Increase the max_frequency entries for clocks that can be driven from pll_a to match the fastest pll_a table entry. Signed-off-by: Stephen Warren Signed-off-by: Colin Cross --- arch/arm/mach-tegra/tegra2_clocks.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c index 692bb845d588..d3e17c1621f7 100644 --- a/arch/arm/mach-tegra/tegra2_clocks.c +++ b/arch/arm/mach-tegra/tegra2_clocks.c @@ -1475,7 +1475,7 @@ static struct clk tegra_pll_a = { .ops = &tegra_pll_ops, .reg = 0xb0, .parent = &tegra_pll_p_out1, - .max_rate = 56448000, + .max_rate = 73728000, .u.pll = { .input_min = 2000000, .input_max = 31000000, @@ -1495,7 +1495,7 @@ static struct clk tegra_pll_a_out0 = { .parent = &tegra_pll_a, .reg = 0xb4, .reg_shift = 0, - .max_rate = 56448000, + .max_rate = 73728000, }; static struct clk_pll_freq_table tegra_pll_d_freq_table[] = { @@ -1694,7 +1694,7 @@ static struct clk tegra_clk_audio = { .name = "audio", .inputs = mux_audio_sync_clk, .reg = 0x38, - .max_rate = 24000000, + .max_rate = 73728000, .ops = &tegra_audio_sync_clk_ops };