phy: usb: Add "wake on" functionality for newer Synopsis XHCI controllers
authorAl Cooper <alcooperx@gmail.com>
Tue, 15 Feb 2022 03:24:21 +0000 (19:24 -0800)
committerVinod Koul <vkoul@kernel.org>
Fri, 25 Feb 2022 08:43:19 +0000 (14:13 +0530)
Add "wake on" support for the newer Synopsis based XHCI only controller.
This works on the 72165 and 72164 and newer chips and does not work
on 7216 based systems. Also switch the USB sysclk to a slower clock
on suspend to save additional power in S2. The clock switch will only
save power on the 72165b0 and newer chips and is a nop on older chips.

Signed-off-by: Al Cooper <alcooperx@gmail.com>
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Link: https://lore.kernel.org/r/20220215032422.5179-1-f.fainelli@gmail.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c

index e63457e..d2524b7 100644 (file)
@@ -47,6 +47,8 @@
 #define   USB_CTRL_USB_PM_SOFT_RESET_MASK              0x40000000
 #define   USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK         0x00800000
 #define   USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK         0x00400000
+#define   USB_CTRL_USB_PM_XHC_PME_EN_MASK              0x00000010
+#define   USB_CTRL_USB_PM_XHC_S2_CLK_SWITCH_EN_MASK    0x00000008
 #define USB_CTRL_USB_PM_STATUS         0x08
 #define USB_CTRL_USB_DEVICE_CTL1       0x10
 #define   USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK      0x00000003
@@ -190,10 +192,6 @@ static void usb_init_common(struct brcm_usb_init_params *params)
 
        pr_debug("%s\n", __func__);
 
-       USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN);
-       /* 1 millisecond - for USB clocks to settle down */
-       usleep_range(1000, 2000);
-
        if (USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE)) {
                reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
                reg &= ~USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE);
@@ -222,6 +220,17 @@ static void usb_wake_enable_7211b0(struct brcm_usb_init_params *params,
                USB_CTRL_UNSET(ctrl, CTLR_CSHCR, ctl_pme_en);
 }
 
+static void usb_wake_enable_7216(struct brcm_usb_init_params *params,
+                                bool enable)
+{
+       void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
+
+       if (enable)
+               USB_CTRL_SET(ctrl, USB_PM, XHC_PME_EN);
+       else
+               USB_CTRL_UNSET(ctrl, USB_PM, XHC_PME_EN);
+}
+
 static void usb_init_common_7211b0(struct brcm_usb_init_params *params)
 {
        void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
@@ -295,6 +304,20 @@ static void usb_init_common_7211b0(struct brcm_usb_init_params *params)
        usb2_eye_fix_7211b0(params);
 }
 
+static void usb_init_common_7216(struct brcm_usb_init_params *params)
+{
+       void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
+
+       USB_CTRL_UNSET(ctrl, USB_PM, XHC_S2_CLK_SWITCH_EN);
+       USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN);
+
+       /* 1 millisecond - for USB clocks to settle down */
+       usleep_range(1000, 2000);
+
+       usb_wake_enable_7216(params, false);
+       usb_init_common(params);
+}
+
 static void usb_init_xhci(struct brcm_usb_init_params *params)
 {
        pr_debug("%s\n", __func__);
@@ -302,14 +325,20 @@ static void usb_init_xhci(struct brcm_usb_init_params *params)
        xhci_soft_reset(params, 0);
 }
 
-static void usb_uninit_common(struct brcm_usb_init_params *params)
+static void usb_uninit_common_7216(struct brcm_usb_init_params *params)
 {
        void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
 
        pr_debug("%s\n", __func__);
 
-       USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN);
+       if (!params->wake_enabled) {
+               USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN);
 
+               /* Switch to using slower clock during suspend to save power */
+               USB_CTRL_SET(ctrl, USB_PM, XHC_S2_CLK_SWITCH_EN);
+       } else {
+               usb_wake_enable_7216(params, true);
+       }
 }
 
 static void usb_uninit_common_7211b0(struct brcm_usb_init_params *params)
@@ -371,9 +400,9 @@ static void usb_set_dual_select(struct brcm_usb_init_params *params, int mode)
 
 static const struct brcm_usb_init_ops bcm7216_ops = {
        .init_ipp = usb_init_ipp,
-       .init_common = usb_init_common,
+       .init_common = usb_init_common_7216,
        .init_xhci = usb_init_xhci,
-       .uninit_common = usb_uninit_common,
+       .uninit_common = usb_uninit_common_7216,
        .uninit_xhci = usb_uninit_xhci,
        .get_dual_select = usb_get_dual_select,
        .set_dual_select = usb_set_dual_select,
@@ -396,6 +425,7 @@ void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params)
 
        params->family_name = "7216";
        params->ops = &bcm7216_ops;
+       params->suspend_with_clocks = true;
 }
 
 void brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params *params)