
Add support for GPCv2 power domains and clock handling for PCIe and PCIe PHY.
Tested-by: Tim Harvey tharvey@gateworks.com #imx8mp-venice* Tested-by: Adam Ford aford173@gmail.com #imx8mp-beacon-kit Reviewed-by: Marek Vasut marex@denx.de Signed-off-by: Sumit Garg sumit.garg@linaro.org --- drivers/power/domain/imx8mp-hsiomix.c | 117 +++++++++++++++++--------- 1 file changed, 79 insertions(+), 38 deletions(-)
diff --git a/drivers/power/domain/imx8mp-hsiomix.c b/drivers/power/domain/imx8mp-hsiomix.c index e2d772c5ec7..d3b0c1146ce 100644 --- a/drivers/power/domain/imx8mp-hsiomix.c +++ b/drivers/power/domain/imx8mp-hsiomix.c @@ -16,48 +16,85 @@ #define GPR_REG0 0x0 #define PCIE_CLOCK_MODULE_EN BIT(0) #define USB_CLOCK_MODULE_EN BIT(1) +#define PCIE_PHY_APB_RST BIT(4) +#define PCIE_PHY_INIT_RST BIT(5)
struct imx8mp_hsiomix_priv { void __iomem *base; struct clk clk_usb; + struct clk clk_pcie; struct power_domain pd_bus; struct power_domain pd_usb; + struct power_domain pd_pcie; struct power_domain pd_usb_phy1; struct power_domain pd_usb_phy2; + struct power_domain pd_pcie_phy; };
-static int imx8mp_hsiomix_on(struct power_domain *power_domain) +static int imx8mp_hsiomix_set(struct power_domain *power_domain, bool power_on) { struct udevice *dev = power_domain->dev; struct imx8mp_hsiomix_priv *priv = dev_get_priv(dev); - struct power_domain *domain; + struct power_domain *domain = NULL; + struct clk *clk = NULL; + u32 gpr_reg0_bits = 0; int ret;
- ret = power_domain_on(&priv->pd_bus); - if (ret) - return ret; - - if (power_domain->id == IMX8MP_HSIOBLK_PD_USB) { + switch (power_domain->id) { + case IMX8MP_HSIOBLK_PD_USB: domain = &priv->pd_usb; - } else if (power_domain->id == IMX8MP_HSIOBLK_PD_USB_PHY1) { + clk = &priv->clk_usb; + gpr_reg0_bits |= USB_CLOCK_MODULE_EN; + break; + case IMX8MP_HSIOBLK_PD_USB_PHY1: domain = &priv->pd_usb_phy1; - } else if (power_domain->id == IMX8MP_HSIOBLK_PD_USB_PHY2) { + break; + case IMX8MP_HSIOBLK_PD_USB_PHY2: domain = &priv->pd_usb_phy2; - } else { - ret = -EINVAL; - goto err_pd; + break; + case IMX8MP_HSIOBLK_PD_PCIE: + domain = &priv->pd_pcie; + clk = &priv->clk_pcie; + gpr_reg0_bits |= PCIE_CLOCK_MODULE_EN; + break; + case IMX8MP_HSIOBLK_PD_PCIE_PHY: + domain = &priv->pd_pcie_phy; + /* Bits to deassert PCIe PHY reset */ + gpr_reg0_bits |= PCIE_PHY_APB_RST | PCIE_PHY_INIT_RST; + break; + default: + dev_err(dev, "unknown power domain id: %ld\n", + power_domain->id); + return -EINVAL; }
- ret = power_domain_on(domain); - if (ret) - goto err_pd; + if (power_on) { + ret = power_domain_on(&priv->pd_bus); + if (ret) + return ret;
- ret = clk_enable(&priv->clk_usb); - if (ret) - goto err_clk; + ret = power_domain_on(domain); + if (ret) + goto err_pd;
- if (power_domain->id == IMX8MP_HSIOBLK_PD_USB) - setbits_le32(priv->base + GPR_REG0, USB_CLOCK_MODULE_EN); + if (clk) { + ret = clk_enable(clk); + if (ret) + goto err_clk; + } + + if (gpr_reg0_bits) + setbits_le32(priv->base + GPR_REG0, gpr_reg0_bits); + } else { + if (gpr_reg0_bits) + clrbits_le32(priv->base + GPR_REG0, gpr_reg0_bits); + + if (clk) + clk_disable(clk); + + power_domain_off(domain); + power_domain_off(&priv->pd_bus); + }
return 0;
@@ -68,26 +105,14 @@ err_pd: return ret; }
-static int imx8mp_hsiomix_off(struct power_domain *power_domain) +static int imx8mp_hsiomix_on(struct power_domain *power_domain) { - struct udevice *dev = power_domain->dev; - struct imx8mp_hsiomix_priv *priv = dev_get_priv(dev); - - if (power_domain->id == IMX8MP_HSIOBLK_PD_USB) - clrbits_le32(priv->base + GPR_REG0, USB_CLOCK_MODULE_EN); - - clk_disable(&priv->clk_usb); - - if (power_domain->id == IMX8MP_HSIOBLK_PD_USB) - power_domain_off(&priv->pd_usb); - else if (power_domain->id == IMX8MP_HSIOBLK_PD_USB_PHY1) - power_domain_off(&priv->pd_usb_phy1); - else if (power_domain->id == IMX8MP_HSIOBLK_PD_USB_PHY2) - power_domain_off(&priv->pd_usb_phy2); - - power_domain_off(&priv->pd_bus); + return imx8mp_hsiomix_set(power_domain, true); +}
- return 0; +static int imx8mp_hsiomix_off(struct power_domain *power_domain) +{ + return imx8mp_hsiomix_set(power_domain, false); }
static int imx8mp_hsiomix_of_xlate(struct power_domain *power_domain, @@ -109,6 +134,10 @@ static int imx8mp_hsiomix_probe(struct udevice *dev) if (ret < 0) return ret;
+ ret = clk_get_by_name(dev, "pcie", &priv->clk_pcie); + if (ret < 0) + return ret; + ret = power_domain_get_by_name(dev, &priv->pd_bus, "bus"); if (ret < 0) return ret; @@ -125,8 +154,20 @@ static int imx8mp_hsiomix_probe(struct udevice *dev) if (ret < 0) goto err_pd_usb_phy2;
+ ret = power_domain_get_by_name(dev, &priv->pd_pcie, "pcie"); + if (ret < 0) + goto err_pd_pcie; + + ret = power_domain_get_by_name(dev, &priv->pd_pcie_phy, "pcie-phy"); + if (ret < 0) + goto err_pd_pcie_phy; + return 0;
+err_pd_pcie_phy: + power_domain_free(&priv->pd_pcie); +err_pd_pcie: + power_domain_free(&priv->pd_usb_phy2); err_pd_usb_phy2: power_domain_free(&priv->pd_usb_phy1); err_pd_usb_phy1: