[PATCH v2 3/8] imx8mp: power-domain: Add PCIe support

Marek Vasut marex at denx.de
Mon Feb 26 09:38:07 CET 2024


On 2/26/24 9:04 AM, Sumit Garg wrote:
> Add support for GPCv2 power domains and clock handling for PCIe and
> PCIe PHY.
> 
> Signed-off-by: Sumit Garg <sumit.garg at linaro.org>
> ---
>   drivers/power/domain/imx8mp-hsiomix.c | 101 ++++++++++++++++++++------
>   1 file changed, 78 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/power/domain/imx8mp-hsiomix.c b/drivers/power/domain/imx8mp-hsiomix.c
> index e2d772c5ec78..58cc3f63bb56 100644
> --- a/drivers/power/domain/imx8mp-hsiomix.c
> +++ b/drivers/power/domain/imx8mp-hsiomix.c
> @@ -16,48 +16,73 @@
>   #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)
>   {
>   	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(&priv->pd_bus);
> +	if (ret)
> +		return ret;
> +
>   	ret = power_domain_on(domain);
>   	if (ret)
>   		goto err_pd;
>   
> -	ret = clk_enable(&priv->clk_usb);
> -	if (ret)
> -		goto err_clk;
> +	if (clk) {
> +		ret = clk_enable(clk);
> +		if (ret)
> +			goto err_clk;
> +	}
>   
> -	if (power_domain->id == IMX8MP_HSIOBLK_PD_USB)
> -		setbits_le32(priv->base + GPR_REG0, USB_CLOCK_MODULE_EN);
> +	setbits_le32(priv->base + GPR_REG0, gpr_reg0_bits);

Are you sure it is OK to do this unconditionally ?

Why not this:

if (gpr_reg0_bits)
   setbits_le32(priv->base + GPR_REG0, gpr_reg0_bits);

>   	return 0;
>   
> @@ -73,17 +98,31 @@ static int imx8mp_hsiomix_off(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)
> +	switch (power_domain->id) {
> +	case 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)
> +		clk_disable(&priv->clk_usb);
>   		power_domain_off(&priv->pd_usb);
> -	else if (power_domain->id == IMX8MP_HSIOBLK_PD_USB_PHY1)
> +		break;
> +	case IMX8MP_HSIOBLK_PD_USB_PHY1:
>   		power_domain_off(&priv->pd_usb_phy1);
> -	else if (power_domain->id == IMX8MP_HSIOBLK_PD_USB_PHY2)
> +		break;
> +	case IMX8MP_HSIOBLK_PD_USB_PHY2:
>   		power_domain_off(&priv->pd_usb_phy2);
> +		break;
> +	case IMX8MP_HSIOBLK_PD_PCIE:

Maybe we need some function ... imx8mp_hsiomix_id_to_pd() to avoid this 
duplicate switch statement:

pd = imx8mp_hsiomix_id_to_pd(...)
...
power_domain_off(fd);

> +		clrbits_le32(priv->base + GPR_REG0, PCIE_CLOCK_MODULE_EN);
> +		clk_disable(&priv->clk_pcie);
> +		power_domain_off(&priv->pd_pcie);
> +		break;
> +	case IMX8MP_HSIOBLK_PD_PCIE_PHY:
> +		clrbits_le32(priv->base + GPR_REG0, PCIE_PHY_APB_RST |
> +						    PCIE_PHY_INIT_RST);
> +		power_domain_off(&priv->pd_pcie_phy);

Is it OK to turn off the bus PD after this ?
Please double-check if power_domain_on/off() is refcounted .

> +		break;
> +	default:
> +		break;
> +	}
>   
>   	power_domain_off(&priv->pd_bus);
>   
> @@ -109,6 +148,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;

Some clk_put() seems to be missing for clk_pcie .


More information about the U-Boot mailing list