Re: [PATCH] xhci: Workaround to get D3 working in Intel xHCI

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Thanks Rajmohan. Comments inline.

On Thu, Jul 9, 2015 at 6:17 PM,  <rajmohan.mani@xxxxxxxxx> wrote:
> From: Rajmohan Mani <rajmohan.mani@xxxxxxxxx>
>
> The xHCI in Intel CherryView / Braswell Platform requires
> a driver workaround to get xHCI D3 working. Without this
> workaround, xHCI might not enter D3.
>
> Workaround is to configure SSIC PORT as "unused" before D3
> entry and "used" after D3 exit. This is done through a
> vendor specific register (PORT2_SSIC_CONFIG_REG2 at offset
> 0x883c), in xhci suspend / resume callbacks.
>
> Verified xHCI D3 works fine in CherryView / Braswell platform.
>
> Signed-off-by: Rajmohan Mani <rajmohan.mani@xxxxxxxxx>
> ---
>  drivers/usb/host/xhci-pci.c | 40 +++++++++++++++++++++++++++++++++++++---
>  1 file changed, 37 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
> index 91260b3..7a69a12 100644
> --- a/drivers/usb/host/xhci-pci.c
> +++ b/drivers/usb/host/xhci-pci.c
> @@ -27,6 +27,10 @@
>  #include "xhci.h"
>  #include "xhci-trace.h"
>
> +#define PORT2_SSIC_CONFIG_REG2 0x883c
> +#define PROG_DONE              (1 << 30)
> +#define SSIC_PORT_UNUSED       (1 << 31)
> +
>  /* Device for a quirk */
>  #define PCI_VENDOR_ID_FRESCO_LOGIC     0x1b73
>  #define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000
> @@ -167,14 +171,44 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
>  }
>
>  /*
> + * In some Intel xHCI controllers, in order to get D3 working,
> + * through a vendor specific SSIC CONFIG register at offset 0x883c,
> + * SSIC PORT need to be marked as "unused" before putting xHCI
> + * into D3. After D3 exit, the SSIC port need to be marked as "used".
> + * Without this change, xHCI might not enter D3 state.
>   * Make sure PME works on some Intel xHCI controllers by writing 1 to clear
>   * the Internal PME flag bit in vendor specific PMCTRL register at offset 0x80a4
>   */
> -static void xhci_pme_quirk(struct xhci_hcd *xhci)
> +static void xhci_pme_quirk(struct usb_hcd *hcd, bool suspend)

Is the function name here still descriptive of the quirk in question?
It seems like the SSIC change is a separate workaround entirely from
the PME quirk that existed here previously, but you're just reusing
this function because it's conveniently called at suspend/resume.

>  {
> +       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
> +       struct pci_dev          *pdev = to_pci_dev(hcd->self.controller);
>         u32 val;
>         void __iomem *reg;
>
> +       if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
> +                pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) {

I would prefer you didn't do this here. Instead, we should keep all of
the vendor/device matching in one place, namely xhci_pci_quirks().
You should create a new quirk name for this ssic D3 workaround, and
match it only to PCI_VENDOR_ID_INTEL &&
PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI in xhci_pci_quirks, for now. Also,
this block should be in a separate function from xhci_pme_quirk.

> +
> +               reg = (void __iomem *) xhci->cap_regs + PORT2_SSIC_CONFIG_REG2;
> +
> +               /* Notify SSIC that SSIC profile programming is not done */
> +               val = readl(reg) & ~PROG_DONE;
> +               writel(val, reg);
> +
> +               /* Mark SSIC port as unused(suspend) or used(resume) */
> +               val = readl(reg);
> +               if (suspend)
> +                       val |= SSIC_PORT_UNUSED;
> +               else
> +                       val &= ~SSIC_PORT_UNUSED;
> +               writel(val, reg);
> +
> +               /* Notify SSIC that SSIC profile programming is done */
> +               val = readl(reg) | PROG_DONE;
> +               writel(val, reg);
> +               readl(reg);
> +       }
> +
>         reg = (void __iomem *) xhci->cap_regs + 0x80a4;
>         val = readl(reg);
>         writel(val | BIT(28), reg);
> @@ -301,7 +335,7 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
>                 pdev->no_d3cold = true;
>
>         if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
> -               xhci_pme_quirk(xhci);
> +               xhci_pme_quirk(hcd, true);
>
>         return xhci_suspend(xhci, do_wakeup);
>  }
> @@ -334,7 +368,7 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
>                 usb_enable_intel_xhci_ports(pdev);
>
>         if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
> -               xhci_pme_quirk(xhci);
> +               xhci_pme_quirk(hcd, false);
>
>         retval = xhci_resume(xhci, hibernated);
>         return retval;
> --
> 1.9.1
>

-- 
Benson Leung
Software Engineer, Chrom* OS
bleung@xxxxxxxxxxxx
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux