diff --git a/arch/arm/mach-tegra/include/mach/usb_phy.h b/arch/arm/mach-tegra/include/mach/usb_phy.h index 71f1b9fa76db..8b4beae773a7 100644 --- a/arch/arm/mach-tegra/include/mach/usb_phy.h +++ b/arch/arm/mach-tegra/include/mach/usb_phy.h @@ -79,6 +79,10 @@ int tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy); int tegra_usb_phy_power_off(struct tegra_usb_phy *phy); +int tegra_usb_phy_preresume(struct tegra_usb_phy *phy); + +int tegra_usb_phy_postresume(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 dffabc3ec063..26605d9c2c0f 100644 --- a/arch/arm/mach-tegra/usb_phy.c +++ b/arch/arm/mach-tegra/usb_phy.c @@ -347,8 +347,6 @@ static void utmi_phy_power_on(struct tegra_usb_phy *phy) val = readl(base + UTMIP_TX_CFG0); val &= ~UTMIP_FS_PREABMLE_J; - if (phy->instance == 2) - val |= UTMIP_HS_DISCON_DISABLE; writel(val, base + UTMIP_TX_CFG0); val = readl(base + UTMIP_HSRX_CFG0); @@ -481,6 +479,26 @@ static void utmi_phy_power_off(struct tegra_usb_phy *phy) utmip_pad_power_off(phy); } +static void utmi_phy_preresume(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + val = readl(base + UTMIP_TX_CFG0); + val |= UTMIP_HS_DISCON_DISABLE; + writel(val, base + UTMIP_TX_CFG0); +} + +static void utmi_phy_postresume(struct tegra_usb_phy *phy) +{ + unsigned long val; + void __iomem *base = phy->regs; + + val = readl(base + UTMIP_TX_CFG0); + val &= ~UTMIP_HS_DISCON_DISABLE; + writel(val, base + UTMIP_TX_CFG0); +} + static void ulpi_viewport_write(struct tegra_usb_phy *phy, u8 addr, u8 data) { unsigned long val; @@ -672,6 +690,20 @@ int tegra_usb_phy_power_off(struct tegra_usb_phy *phy) return 0; } +int tegra_usb_phy_preresume(struct tegra_usb_phy *phy) +{ + if (phy->instance == 2) + utmi_phy_preresume(phy); + return 0; +} + +int tegra_usb_phy_postresume(struct tegra_usb_phy *phy) +{ + if (phy->instance == 2) + utmi_phy_postresume(phy); + return 0; +} + int tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy) { if (phy->instance != 1) diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 635dced2e82b..ef1093f9dd26 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -259,6 +259,7 @@ static int tegra_sdhci_suspend(struct platform_device *pdev, pm_message_t state) if (ret) pr_err("%s: failed, error = %d\n", __func__, ret); + tegra_sdhci_enable_clock(host, 0); return ret; } diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 972d5ddd1e18..116347b0bf13 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -159,6 +159,25 @@ static const u32 oid_supported_list [] = #endif /* RNDIS_PM */ }; +/* HACK: copied from net/core/dev.c to replace dev_get_stats since + * dev_get_stats cannot be called from atomic context */ +static void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64, + const struct net_device_stats *netdev_stats) +{ +#if BITS_PER_LONG == 64 + BUILD_BUG_ON(sizeof(*stats64) != sizeof(*netdev_stats)); + memcpy(stats64, netdev_stats, sizeof(*stats64)); +#else + size_t i, n = sizeof(*stats64) / sizeof(u64); + const unsigned long *src = (const unsigned long *)netdev_stats; + u64 *dst = (u64 *)stats64; + + BUILD_BUG_ON(sizeof(*netdev_stats) / sizeof(unsigned long) != + sizeof(*stats64) / sizeof(u64)); + for (i = 0; i < n; i++) + dst[i] = src[i]; +#endif +} /* NDIS Functions */ static int @@ -172,7 +191,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, rndis_query_cmplt_type *resp; struct net_device *net; struct rtnl_link_stats64 temp; - const struct rtnl_link_stats64 *stats; + struct rtnl_link_stats64 *stats = &temp; if (!r) return -ENOMEM; resp = (rndis_query_cmplt_type *) r->buf; @@ -195,7 +214,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, resp->InformationBufferOffset = cpu_to_le32 (16); net = rndis_per_dev_params[configNr].dev; - stats = dev_get_stats(net, &temp); + netdev_stats_to_stats64(stats, &net->stats); switch (OID) { diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index e566a97f21dc..e3b01b39fc3f 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -50,6 +50,7 @@ struct tegra_ehci_hcd { struct otg_transceiver *transceiver; int host_resumed; int bus_suspended; + int port_resuming; struct tegra_ehci_context context; int power_down_on_bus_suspend; }; @@ -82,6 +83,7 @@ static int tegra_ehci_hub_control( ) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); u32 __iomem *status_reg; u32 temp; unsigned long flags; @@ -94,7 +96,7 @@ static int tegra_ehci_hub_control( * that are write on clear, by writing back the register read value, so * USB_PORT_FEAT_ENABLE is handled by masking the set on clear bits */ - if ((typeReq == ClearPortFeature) && (wValue == USB_PORT_FEAT_ENABLE)) { + if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_ENABLE) { spin_lock_irqsave(&ehci->lock, flags); temp = ehci_readl(ehci, status_reg); ehci_writel(ehci, (temp & ~PORT_RWC_BITS) & ~PORT_PE, status_reg); @@ -102,6 +104,85 @@ static int tegra_ehci_hub_control( return retval; } + if (typeReq == GetPortStatus) { + spin_lock_irqsave(&ehci->lock, flags); + temp = ehci_readl(ehci, status_reg); + if (tegra->port_resuming && !(temp & PORT_SUSPEND)) { + /* resume completed */ + tegra->port_resuming = 0; + tegra_usb_phy_postresume(tegra->phy); + } + spin_unlock_irqrestore(&ehci->lock, flags); + } + + if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) { + spin_lock_irqsave(&ehci->lock, flags); + temp = ehci_readl(ehci, status_reg); + if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) + retval = -EPIPE; + + /* After above check the port must be connected. + * Set appropriate bit thus could put phy into low power + * mode if we have hostpc feature + */ + temp &= ~PORT_WKCONN_E; + temp |= PORT_WKDISC_E | PORT_WKOC_E; + ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); + if (handshake(ehci, status_reg, PORT_SUSPEND, + PORT_SUSPEND, 5000)) + pr_err("%s: timeout waiting for PORT_SUSPEND\n", __func__); + spin_unlock_irqrestore(&ehci->lock, flags); + return retval; + } + + /* + * Tegra host controller will time the resume operation to clear the bit + * when the port control state switches to HS or FS Idle. This behavior + * is different from EHCI where the host controller driver is required + * to set this bit to a zero after the resume duration is timed in the + * driver. + */ + if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_SUSPEND) { + spin_lock_irqsave(&ehci->lock, flags); + temp = ehci_readl(ehci, status_reg); + if ((temp & PORT_RESET) || !(temp & PORT_PE)) + retval = -EPIPE; + + if (!(temp & PORT_SUSPEND)) { + spin_unlock_irqrestore(&ehci->lock, flags); + return retval; + } + + 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 */ + ehci_writel(ehci, temp | PORT_RESUME, status_reg); + + /* polling PORT_RESUME until the controller clear this bit */ + if (handshake(ehci, status_reg, PORT_RESUME, 0, 20000)) + pr_err("%s: timeout waiting for PORT_RESUME\n", __func__); + + /* write PORT_RESUME to 0 to clear PORT_SUSPEND bit */ + temp &= ~(PORT_RESUME | PORT_SUSPEND); + ehci_writel(ehci, temp, status_reg); + + /* polling PORT_SUSPEND until the controller clear this bit */ + if (handshake(ehci, status_reg, PORT_SUSPEND, 0, 2000)) + pr_err("%s: timeout waiting for PORT_SUSPEND\n", __func__); + + tegra->port_resuming = 1; + + spin_unlock_irqrestore(&ehci->lock, flags); + return retval; + } + /* Handle the hub control events here */ return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); } @@ -357,6 +438,8 @@ static int tegra_ehci_bus_resume(struct usb_hcd *hcd) tegra->bus_suspended = 0; } + tegra_usb_phy_preresume(tegra->phy); + tegra->port_resuming = 1; return ehci_bus_resume(hcd); } diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c index 15a4f5b472a8..cc26c5977a20 100644 --- a/drivers/video/tegra/fb.c +++ b/drivers/video/tegra/fb.c @@ -198,6 +198,10 @@ static int tegra_fb_setcolreg(unsigned regno, unsigned red, unsigned green, if (regno >= 16) return -EINVAL; + red = (red >> (16 - info->var.red.length)); + green = (green >> (16 - info->var.green.length)); + blue = (blue >> (16 - info->var.blue.length)); + v = (red << var->red.offset) | (green << var->green.offset) | (blue << var->blue.offset); diff --git a/drivers/video/tegra/host/dev.c b/drivers/video/tegra/host/dev.c index daed882be5a2..42d268e7da59 100644 --- a/drivers/video/tegra/host/dev.c +++ b/drivers/video/tegra/host/dev.c @@ -452,7 +452,7 @@ static int nvhost_ioctl_ctrl_module_mutex( struct nvhost_ctrl_module_mutex_args *args) { int err = 0; - if (args->id >= NV_HOST1X_SYNCPT_NB_PTS || + if (args->id >= NV_HOST1X_NB_MLOCKS || args->lock > 1) return -EINVAL;