diff options
author | Rafał Miłecki <rafal@milecki.pl> | 2021-01-14 12:13:49 +0100 |
---|---|---|
committer | Rafał Miłecki <rafal@milecki.pl> | 2021-01-14 12:34:20 +0100 |
commit | 6c90999e2e0dee6e5e0322b89e8e6fb6f76aecc9 (patch) | |
tree | bf909eecacb6c901e37b8969f1b79c61e16a0b54 /target/linux/bcm4908/patches-5.4/084-v5.6-0004-phy-usb-Add-wake-on-functionality.patch | |
parent | fa02225ee656c18b084988246a0ad83fb202c374 (diff) | |
download | upstream-6c90999e2e0dee6e5e0322b89e8e6fb6f76aecc9.tar.gz upstream-6c90999e2e0dee6e5e0322b89e8e6fb6f76aecc9.tar.bz2 upstream-6c90999e2e0dee6e5e0322b89e8e6fb6f76aecc9.zip |
bcm4908: backport brcmstb USB PHY driver changes
This includes BCM4908 support
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Diffstat (limited to 'target/linux/bcm4908/patches-5.4/084-v5.6-0004-phy-usb-Add-wake-on-functionality.patch')
-rw-r--r-- | target/linux/bcm4908/patches-5.4/084-v5.6-0004-phy-usb-Add-wake-on-functionality.patch | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/target/linux/bcm4908/patches-5.4/084-v5.6-0004-phy-usb-Add-wake-on-functionality.patch b/target/linux/bcm4908/patches-5.4/084-v5.6-0004-phy-usb-Add-wake-on-functionality.patch new file mode 100644 index 0000000000..d52edfef77 --- /dev/null +++ b/target/linux/bcm4908/patches-5.4/084-v5.6-0004-phy-usb-Add-wake-on-functionality.patch @@ -0,0 +1,205 @@ +From f1c0db40a3ade1f1a39e5794d728f2953d817322 Mon Sep 17 00:00:00 2001 +From: Al Cooper <alcooperx@gmail.com> +Date: Fri, 3 Jan 2020 13:18:02 -0500 +Subject: [PATCH] phy: usb: Add "wake on" functionality + +Add the ability to handle USB wake events from USB devices when +in S2 mode. Typically there is some additional configuration +needed to tell the USB device to generate the wake event when +suspended but this varies with the different USB device classes. +For example, on USB Ethernet dongles, ethtool should be used to +enable the magic packet wake functionality in the dongle. +NOTE: This requires that the "power/wakeup" sysfs entry for +the USB device generating the wakeup be set to "enabled". + +This functionality requires a special hardware sideband path that +will trigger the AON_PM_L2 interrupt needed to wake the system from +S2 even though the USB host controllers are in IDDQ (low power state) +and most USB related clocks are shut off. For the sideband signaling +to work we need to leave the usbx_freerun clock running, but this +clock consumes very little power by design. There's a bug in the +XHCI wake hardware so only EHCI/OHCI wake is currently supported. + +Signed-off-by: Al Cooper <alcooperx@gmail.com> +Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> +Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com> +--- + drivers/phy/broadcom/phy-brcm-usb-init.c | 17 +++++++++ + drivers/phy/broadcom/phy-brcm-usb-init.h | 1 + + drivers/phy/broadcom/phy-brcm-usb.c | 48 ++++++++++++++++++++++-- + 3 files changed, 63 insertions(+), 3 deletions(-) + +--- a/drivers/phy/broadcom/phy-brcm-usb-init.c ++++ b/drivers/phy/broadcom/phy-brcm-usb-init.c +@@ -58,6 +58,8 @@ + #define USB_CTRL_USB_PM_SOFT_RESET_MASK 0x40000000 /* option */ + #define USB_CTRL_USB_PM_USB20_HC_RESETB_MASK 0x30000000 /* option */ + #define USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK 0x00300000 /* option */ ++#define USB_CTRL_USB_PM_RMTWKUP_EN_MASK 0x00000001 ++#define USB_CTRL_USB_PM_STATUS 0x38 + #define USB_CTRL_USB30_CTL1 0x60 + #define USB_CTRL_USB30_CTL1_PHY3_PLL_SEQ_START_MASK 0x00000010 + #define USB_CTRL_USB30_CTL1_PHY3_RESETB_MASK 0x00010000 +@@ -855,6 +857,10 @@ void brcm_usb_init_common(struct brcm_us + u32 reg; + void __iomem *ctrl = params->ctrl_regs; + ++ /* Clear any pending wake conditions */ ++ reg = brcmusb_readl(USB_CTRL_REG(ctrl, USB_PM_STATUS)); ++ brcmusb_writel(reg, USB_CTRL_REG(ctrl, USB_PM_STATUS)); ++ + /* Take USB out of power down */ + if (USB_CTRL_MASK_FAMILY(params, PLL_CTL, PLL_IDDQ_PWRDN)) { + USB_CTRL_UNSET_FAMILY(params, PLL_CTL, PLL_IDDQ_PWRDN); +@@ -1010,6 +1016,17 @@ void brcm_usb_uninit_xhci(struct brcm_us + USB_CTRL_SET(params->ctrl_regs, USB30_PCTL, PHY3_IDDQ_OVERRIDE); + } + ++void brcm_usb_wake_enable(struct brcm_usb_init_params *params, ++ int enable) ++{ ++ void __iomem *ctrl = params->ctrl_regs; ++ ++ if (enable) ++ USB_CTRL_SET(ctrl, USB_PM, RMTWKUP_EN); ++ else ++ USB_CTRL_UNSET(ctrl, USB_PM, RMTWKUP_EN); ++} ++ + void brcm_usb_set_family_map(struct brcm_usb_init_params *params) + { + int fam; +--- a/drivers/phy/broadcom/phy-brcm-usb-init.h ++++ b/drivers/phy/broadcom/phy-brcm-usb-init.h +@@ -38,5 +38,6 @@ void brcm_usb_init_xhci(struct brcm_usb_ + void brcm_usb_uninit_common(struct brcm_usb_init_params *ini); + void brcm_usb_uninit_eohci(struct brcm_usb_init_params *ini); + void brcm_usb_uninit_xhci(struct brcm_usb_init_params *ini); ++void brcm_usb_wake_enable(struct brcm_usb_init_params *params, int enable); + + #endif /* _USB_BRCM_COMMON_INIT_H */ +--- a/drivers/phy/broadcom/phy-brcm-usb.c ++++ b/drivers/phy/broadcom/phy-brcm-usb.c +@@ -57,11 +57,22 @@ struct brcm_usb_phy_data { + bool has_xhci; + struct clk *usb_20_clk; + struct clk *usb_30_clk; ++ struct clk *suspend_clk; + struct mutex mutex; /* serialize phy init */ + int init_count; ++ int wake_irq; + struct brcm_usb_phy phys[BRCM_USB_PHY_ID_MAX]; + }; + ++static irqreturn_t brcm_usb_phy_wake_isr(int irq, void *dev_id) ++{ ++ struct phy *gphy = dev_id; ++ ++ pm_wakeup_event(&gphy->dev, 0); ++ ++ return IRQ_HANDLED; ++} ++ + static int brcm_usb_phy_init(struct phy *gphy) + { + struct brcm_usb_phy *phy = phy_get_drvdata(gphy); +@@ -76,6 +87,7 @@ static int brcm_usb_phy_init(struct phy + if (priv->init_count++ == 0) { + clk_prepare_enable(priv->usb_20_clk); + clk_prepare_enable(priv->usb_30_clk); ++ clk_prepare_enable(priv->suspend_clk); + brcm_usb_init_common(&priv->ini); + } + mutex_unlock(&priv->mutex); +@@ -108,6 +120,7 @@ static int brcm_usb_phy_exit(struct phy + brcm_usb_uninit_common(&priv->ini); + clk_disable_unprepare(priv->usb_20_clk); + clk_disable_unprepare(priv->usb_30_clk); ++ clk_disable_unprepare(priv->suspend_clk); + } + mutex_unlock(&priv->mutex); + phy->inited = false; +@@ -228,11 +241,12 @@ static const struct attribute_group brcm + .attrs = brcm_usb_phy_attrs, + }; + +-static int brcm_usb_phy_dvr_init(struct device *dev, ++static int brcm_usb_phy_dvr_init(struct platform_device *pdev, + struct brcm_usb_phy_data *priv, + struct device_node *dn) + { +- struct phy *gphy; ++ struct device *dev = &pdev->dev; ++ struct phy *gphy = NULL; + int err; + + priv->usb_20_clk = of_clk_get_by_name(dn, "sw_usb"); +@@ -275,6 +289,28 @@ static int brcm_usb_phy_dvr_init(struct + if (err) + return err; + } ++ ++ priv->suspend_clk = clk_get(dev, "usb0_freerun"); ++ if (IS_ERR(priv->suspend_clk)) { ++ dev_err(dev, "Suspend Clock not found in Device Tree\n"); ++ priv->suspend_clk = NULL; ++ } ++ ++ priv->wake_irq = platform_get_irq_byname(pdev, "wake"); ++ if (priv->wake_irq < 0) ++ priv->wake_irq = platform_get_irq_byname(pdev, "wakeup"); ++ if (priv->wake_irq >= 0) { ++ err = devm_request_irq(dev, priv->wake_irq, ++ brcm_usb_phy_wake_isr, 0, ++ dev_name(dev), gphy); ++ if (err < 0) ++ return err; ++ device_set_wakeup_capable(dev, 1); ++ } else { ++ dev_info(dev, ++ "Wake interrupt missing, system wake not supported\n"); ++ } ++ + return 0; + } + +@@ -335,7 +371,7 @@ static int brcm_usb_phy_probe(struct pla + if (of_property_read_bool(dn, "brcm,has-eohci")) + priv->has_eohci = true; + +- err = brcm_usb_phy_dvr_init(dev, priv, dn); ++ err = brcm_usb_phy_dvr_init(pdev, priv, dn); + if (err) + return err; + +@@ -386,10 +422,13 @@ static int brcm_usb_phy_suspend(struct d + if (priv->phys[BRCM_USB_PHY_2_0].inited) + brcm_usb_uninit_eohci(&priv->ini); + brcm_usb_uninit_common(&priv->ini); ++ brcm_usb_wake_enable(&priv->ini, true); + if (priv->phys[BRCM_USB_PHY_3_0].inited) + clk_disable_unprepare(priv->usb_30_clk); + if (priv->phys[BRCM_USB_PHY_2_0].inited) + clk_disable_unprepare(priv->usb_20_clk); ++ if (priv->wake_irq >= 0) ++ enable_irq_wake(priv->wake_irq); + } + return 0; + } +@@ -400,6 +439,7 @@ static int brcm_usb_phy_resume(struct de + + clk_prepare_enable(priv->usb_20_clk); + clk_prepare_enable(priv->usb_30_clk); ++ brcm_usb_wake_enable(&priv->ini, false); + brcm_usb_init_ipp(&priv->ini); + + /* +@@ -407,6 +447,8 @@ static int brcm_usb_phy_resume(struct de + * Uninitialize anything that wasn't previously initialized. + */ + if (priv->init_count) { ++ if (priv->wake_irq >= 0) ++ disable_irq_wake(priv->wake_irq); + brcm_usb_init_common(&priv->ini); + if (priv->phys[BRCM_USB_PHY_2_0].inited) { + brcm_usb_init_eohci(&priv->ini); |