imx8mp: power-domain: Add PCIe support
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>
diff --git a/drivers/power/domain/imx8mp-hsiomix.c b/drivers/power/domain/imx8mp-hsiomix.c
index e2d772c..d3b0c11 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 @@
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 @@
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 @@
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: