aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm4908/patches-5.4/084-v5.6-0013-phy-usb-Add-support-for-wake-and-USB-low-power-mode-.patch
diff options
context:
space:
mode:
authorRafał Miłecki <rafal@milecki.pl>2021-01-14 12:13:49 +0100
committerRafał Miłecki <rafal@milecki.pl>2021-01-14 12:34:20 +0100
commit6c90999e2e0dee6e5e0322b89e8e6fb6f76aecc9 (patch)
treebf909eecacb6c901e37b8969f1b79c61e16a0b54 /target/linux/bcm4908/patches-5.4/084-v5.6-0013-phy-usb-Add-support-for-wake-and-USB-low-power-mode-.patch
parentfa02225ee656c18b084988246a0ad83fb202c374 (diff)
downloadupstream-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-0013-phy-usb-Add-support-for-wake-and-USB-low-power-mode-.patch')
-rw-r--r--target/linux/bcm4908/patches-5.4/084-v5.6-0013-phy-usb-Add-support-for-wake-and-USB-low-power-mode-.patch328
1 files changed, 328 insertions, 0 deletions
diff --git a/target/linux/bcm4908/patches-5.4/084-v5.6-0013-phy-usb-Add-support-for-wake-and-USB-low-power-mode-.patch b/target/linux/bcm4908/patches-5.4/084-v5.6-0013-phy-usb-Add-support-for-wake-and-USB-low-power-mode-.patch
new file mode 100644
index 0000000000..5a3a687adb
--- /dev/null
+++ b/target/linux/bcm4908/patches-5.4/084-v5.6-0013-phy-usb-Add-support-for-wake-and-USB-low-power-mode-.patch
@@ -0,0 +1,328 @@
+From b0c0b66c0b432d3f3a1ae5849298ba9c7f1810c5 Mon Sep 17 00:00:00 2001
+From: Al Cooper <alcooperx@gmail.com>
+Date: Fri, 3 Jan 2020 13:18:11 -0500
+Subject: [PATCH] phy: usb: Add support for wake and USB low power mode for
+ 7211 S2/S5
+
+Add support for 7211 USB wake. Disable all possible 7211 USB logic
+for S2/S5 if USB wake is not enabled.
+
+On the 7211, the XHCI wake signal was not connected properly and
+only goes to the USB1_USB1_CTRL_TP_DIAG1 diagonstic register.
+The workaround is to have VPU code running that polls for the
+proper bit in the DIAG register and to wake the system when
+the bit is asserted.
+
+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>
+---
+ .../phy/broadcom/phy-brcm-usb-init-synopsys.c | 77 +++++++++++++++++--
+ drivers/phy/broadcom/phy-brcm-usb-init.c | 26 ++++---
+ drivers/phy/broadcom/phy-brcm-usb-init.h | 11 +--
+ drivers/phy/broadcom/phy-brcm-usb.c | 25 ++++--
+ 4 files changed, 105 insertions(+), 34 deletions(-)
+
+--- a/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c
++++ b/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c
+@@ -26,7 +26,6 @@
+ #define PIARBCTL_MISC_CAM1_MEM_PAGE_MASK 0x00000f00
+ #define PIARBCTL_MISC_CAM0_MEM_PAGE_MASK 0x000000f0
+ #define PIARBCTL_MISC_SATA_PRIORITY_MASK 0x0000000f
+-#define PIARBCTL_USB_M_ASB_CTRL 0x10
+
+ #define PIARBCTL_MISC_USB_ONLY_MASK \
+ (PIARBCTL_MISC_USB_SELECT_MASK | \
+@@ -51,14 +50,27 @@
+ #define USB_CTRL_USB_PM_STATUS 0x08
+ #define USB_CTRL_USB_DEVICE_CTL1 0x10
+ #define USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK 0x00000003
++#define USB_CTRL_TEST_PORT_CTL 0x30
++#define USB_CTRL_TEST_PORT_CTL_TPOUT_SEL_MASK 0x000000ff
++#define USB_CTRL_TEST_PORT_CTL_TPOUT_SEL_PME_GEN_MASK 0x0000002e
++#define USB_CTRL_TP_DIAG1 0x34
++#define USB_CTLR_TP_DIAG1_wake_MASK 0x00000002
++#define USB_CTRL_CTLR_CSHCR 0x50
++#define USB_CTRL_CTLR_CSHCR_ctl_pme_en_MASK 0x00040000
+
+ /* Register definitions for the USB_PHY block in 7211b0 */
++#define USB_PHY_PLL_CTL 0x00
++#define USB_PHY_PLL_CTL_PLL_RESETB_MASK 0x40000000
+ #define USB_PHY_PLL_LDO_CTL 0x08
+ #define USB_PHY_PLL_LDO_CTL_AFE_CORERDY_MASK 0x00000004
++#define USB_PHY_PLL_LDO_CTL_AFE_LDO_PWRDWNB_MASK 0x00000002
++#define USB_PHY_PLL_LDO_CTL_AFE_BG_PWRDWNB_MASK 0x00000001
+ #define USB_PHY_UTMI_CTL_1 0x04
+ #define USB_PHY_UTMI_CTL_1_POWER_UP_FSM_EN_MASK 0x00000800
+ #define USB_PHY_UTMI_CTL_1_PHY_MODE_MASK 0x0000000c
+ #define USB_PHY_UTMI_CTL_1_PHY_MODE_SHIFT 2
++#define USB_PHY_IDDQ 0x1c
++#define USB_PHY_IDDQ_phy_iddq_MASK 0x00000001
+ #define USB_PHY_STATUS 0x20
+ #define USB_PHY_STATUS_pll_lock_MASK 0x00000001
+
+@@ -199,6 +211,17 @@ static void usb_init_common(struct brcm_
+ }
+ }
+
++static void usb_wake_enable_7211b0(struct brcm_usb_init_params *params,
++ bool enable)
++{
++ void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
++
++ if (enable)
++ USB_CTRL_SET(ctrl, CTLR_CSHCR, ctl_pme_en);
++ else
++ USB_CTRL_UNSET(ctrl, CTLR_CSHCR, ctl_pme_en);
++}
++
+ static void usb_init_common_7211b0(struct brcm_usb_init_params *params)
+ {
+ void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
+@@ -210,9 +233,27 @@ static void usb_init_common_7211b0(struc
+ if (params->syscon_piarbctl)
+ syscon_piarbctl_init(params->syscon_piarbctl);
+
++ USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN);
++
++ usb_wake_enable_7211b0(params, false);
++ if (!params->wake_enabled) {
++
++ /* undo possible suspend settings */
++ brcm_usb_writel(0, usb_phy + USB_PHY_IDDQ);
++ reg = brcm_usb_readl(usb_phy + USB_PHY_PLL_CTL);
++ reg |= USB_PHY_PLL_CTL_PLL_RESETB_MASK;
++ brcm_usb_writel(reg, usb_phy + USB_PHY_PLL_CTL);
++
++ /* temporarily enable FSM so PHY comes up properly */
++ reg = brcm_usb_readl(usb_phy + USB_PHY_UTMI_CTL_1);
++ reg |= USB_PHY_UTMI_CTL_1_POWER_UP_FSM_EN_MASK;
++ brcm_usb_writel(reg, usb_phy + USB_PHY_UTMI_CTL_1);
++ }
++
+ /* Init the PHY */
+- reg = brcm_usb_readl(usb_phy + USB_PHY_PLL_LDO_CTL);
+- reg |= USB_PHY_PLL_LDO_CTL_AFE_CORERDY_MASK;
++ reg = USB_PHY_PLL_LDO_CTL_AFE_CORERDY_MASK |
++ USB_PHY_PLL_LDO_CTL_AFE_LDO_PWRDWNB_MASK |
++ USB_PHY_PLL_LDO_CTL_AFE_BG_PWRDWNB_MASK;
+ brcm_usb_writel(reg, usb_phy + USB_PHY_PLL_LDO_CTL);
+
+ /* wait for lock */
+@@ -276,12 +317,36 @@ static void usb_uninit_common(struct brc
+
+ }
+
++static void usb_uninit_common_7211b0(struct brcm_usb_init_params *params)
++{
++ void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
++ void __iomem *usb_phy = params->regs[BRCM_REGS_USB_PHY];
++ u32 reg;
++
++ pr_debug("%s\n", __func__);
++
++ if (params->wake_enabled) {
++ USB_CTRL_SET(ctrl, TEST_PORT_CTL, TPOUT_SEL_PME_GEN);
++ usb_wake_enable_7211b0(params, true);
++ } else {
++ USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN);
++ brcm_usb_writel(0, usb_phy + USB_PHY_PLL_LDO_CTL);
++ reg = brcm_usb_readl(usb_phy + USB_PHY_PLL_CTL);
++ reg &= ~USB_PHY_PLL_CTL_PLL_RESETB_MASK;
++ brcm_usb_writel(reg, usb_phy + USB_PHY_PLL_CTL);
++ brcm_usb_writel(USB_PHY_IDDQ_phy_iddq_MASK,
++ usb_phy + USB_PHY_IDDQ);
++ }
++
++}
++
+ static void usb_uninit_xhci(struct brcm_usb_init_params *params)
+ {
+
+ pr_debug("%s\n", __func__);
+
+- xhci_soft_reset(params, 1);
++ if (!params->wake_enabled)
++ xhci_soft_reset(params, 1);
+ }
+
+ static int usb_get_dual_select(struct brcm_usb_init_params *params)
+@@ -309,7 +374,6 @@ static void usb_set_dual_select(struct b
+ brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
+ }
+
+-
+ static const struct brcm_usb_init_ops bcm7216_ops = {
+ .init_ipp = usb_init_ipp,
+ .init_common = usb_init_common,
+@@ -324,7 +388,7 @@ static const struct brcm_usb_init_ops bc
+ .init_ipp = usb_init_ipp,
+ .init_common = usb_init_common_7211b0,
+ .init_xhci = usb_init_xhci,
+- .uninit_common = usb_uninit_common,
++ .uninit_common = usb_uninit_common_7211b0,
+ .uninit_xhci = usb_uninit_xhci,
+ .get_dual_select = usb_get_dual_select,
+ .set_dual_select = usb_set_dual_select,
+@@ -346,4 +410,5 @@ void brcm_usb_dvr_init_7211b0(struct brc
+
+ params->family_name = "7211";
+ params->ops = &bcm7211b0_ops;
++ params->suspend_with_clocks = true;
+ }
+--- a/drivers/phy/broadcom/phy-brcm-usb-init.c
++++ b/drivers/phy/broadcom/phy-brcm-usb-init.c
+@@ -783,12 +783,24 @@ static void usb_init_ipp(struct brcm_usb
+ msleep(50);
+ }
+
++static void usb_wake_enable(struct brcm_usb_init_params *params,
++ bool enable)
++{
++ void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
++
++ if (enable)
++ USB_CTRL_SET(ctrl, USB_PM, RMTWKUP_EN);
++ else
++ USB_CTRL_UNSET(ctrl, USB_PM, RMTWKUP_EN);
++}
++
+ static void usb_init_common(struct brcm_usb_init_params *params)
+ {
+ u32 reg;
+ void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
+
+ /* Clear any pending wake conditions */
++ usb_wake_enable(params, false);
+ reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_PM_STATUS));
+ brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_PM_STATUS));
+
+@@ -935,6 +947,8 @@ static void usb_uninit_common(struct brc
+
+ if (USB_CTRL_MASK_FAMILY(params, PLL_CTL, PLL_IDDQ_PWRDN))
+ USB_CTRL_SET_FAMILY(params, PLL_CTL, PLL_IDDQ_PWRDN);
++ if (params->wake_enabled)
++ usb_wake_enable(params, true);
+ }
+
+ static void usb_uninit_eohci(struct brcm_usb_init_params *params)
+@@ -978,17 +992,6 @@ static void usb_set_dual_select(struct b
+ }
+ }
+
+-static void usb_wake_enable(struct brcm_usb_init_params *params,
+- int enable)
+-{
+- void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
+-
+- if (enable)
+- USB_CTRL_SET(ctrl, USB_PM, RMTWKUP_EN);
+- else
+- USB_CTRL_UNSET(ctrl, USB_PM, RMTWKUP_EN);
+-}
+-
+ static const struct brcm_usb_init_ops bcm7445_ops = {
+ .init_ipp = usb_init_ipp,
+ .init_common = usb_init_common,
+@@ -999,7 +1002,6 @@ static const struct brcm_usb_init_ops bc
+ .uninit_xhci = usb_uninit_xhci,
+ .get_dual_select = usb_get_dual_select,
+ .set_dual_select = usb_set_dual_select,
+- .wake_enable = usb_wake_enable,
+ };
+
+ void brcm_usb_dvr_init_7445(struct brcm_usb_init_params *params)
+--- a/drivers/phy/broadcom/phy-brcm-usb-init.h
++++ b/drivers/phy/broadcom/phy-brcm-usb-init.h
+@@ -46,8 +46,6 @@ struct brcm_usb_init_ops {
+ void (*uninit_xhci)(struct brcm_usb_init_params *params);
+ int (*get_dual_select)(struct brcm_usb_init_params *params);
+ void (*set_dual_select)(struct brcm_usb_init_params *params, int mode);
+- void (*wake_enable)(struct brcm_usb_init_params *params,
+- int enable);
+ };
+
+ struct brcm_usb_init_params {
+@@ -62,6 +60,8 @@ struct brcm_usb_init_params {
+ const u32 *usb_reg_bits_map;
+ const struct brcm_usb_init_ops *ops;
+ struct regmap *syscon_piarbctl;
++ bool wake_enabled;
++ bool suspend_with_clocks;
+ };
+
+ void brcm_usb_dvr_init_7445(struct brcm_usb_init_params *params);
+@@ -145,13 +145,6 @@ static inline void brcm_usb_uninit_xhci(
+ ini->ops->uninit_xhci(ini);
+ }
+
+-static inline void brcm_usb_wake_enable(struct brcm_usb_init_params *ini,
+- int enable)
+-{
+- if (ini->ops->wake_enable)
+- ini->ops->wake_enable(ini, enable);
+-}
+-
+ static inline int brcm_usb_get_dual_select(struct brcm_usb_init_params *ini)
+ {
+ if (ini->ops->get_dual_select)
+--- a/drivers/phy/broadcom/phy-brcm-usb.c
++++ b/drivers/phy/broadcom/phy-brcm-usb.c
+@@ -535,16 +535,26 @@ static int brcm_usb_phy_suspend(struct d
+ struct brcm_usb_phy_data *priv = dev_get_drvdata(dev);
+
+ if (priv->init_count) {
++ priv->ini.wake_enabled = device_may_wakeup(dev);
+ if (priv->phys[BRCM_USB_PHY_3_0].inited)
+ brcm_usb_uninit_xhci(&priv->ini);
+ 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 || !priv->has_eohci)
+- clk_disable_unprepare(priv->usb_20_clk);
++
++ /*
++ * Handle the clocks unless needed for wake. This has
++ * to work for both older XHCI->3.0-clks, EOHCI->2.0-clks
++ * and newer XHCI->2.0-clks/3.0-clks.
++ */
++
++ if (!priv->ini.suspend_with_clocks) {
++ 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 ||
++ !priv->has_eohci)
++ clk_disable_unprepare(priv->usb_20_clk);
++ }
+ if (priv->wake_irq >= 0)
+ enable_irq_wake(priv->wake_irq);
+ }
+@@ -557,7 +567,6 @@ 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);
+
+ /*
+@@ -579,6 +588,8 @@ static int brcm_usb_phy_resume(struct de
+ } else if (priv->has_xhci) {
+ brcm_usb_uninit_xhci(&priv->ini);
+ clk_disable_unprepare(priv->usb_30_clk);
++ if (!priv->has_eohci)
++ clk_disable_unprepare(priv->usb_20_clk);
+ }
+ } else {
+ if (priv->has_xhci)
+@@ -589,7 +600,7 @@ static int brcm_usb_phy_resume(struct de
+ clk_disable_unprepare(priv->usb_20_clk);
+ clk_disable_unprepare(priv->usb_30_clk);
+ }
+-
++ priv->ini.wake_enabled = false;
+ return 0;
+ }
+ #endif /* CONFIG_PM_SLEEP */