mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-29 10:08:59 +00:00
6c90999e2e
This includes BCM4908 support Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
329 lines
11 KiB
Diff
329 lines
11 KiB
Diff
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 */
|