diff options
Diffstat (limited to 'drivers/soc/imx/gpcv2.c')
| -rw-r--r-- | drivers/soc/imx/gpcv2.c | 134 | 
1 files changed, 93 insertions, 41 deletions
diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index 34a9ac1f2b9b..b8d52d8d29db 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -192,7 +192,7 @@ struct imx_pgc_domain {  	struct clk_bulk_data *clks;  	int num_clks; -	unsigned int pgc; +	unsigned long pgc;  	const struct {  		u32 pxx; @@ -202,6 +202,7 @@ struct imx_pgc_domain {  	} bits;  	const int voltage; +	const bool keep_clocks;  	struct device *dev;  }; @@ -220,7 +221,7 @@ to_imx_pgc_domain(struct generic_pm_domain *genpd)  static int imx_pgc_power_up(struct generic_pm_domain *genpd)  {  	struct imx_pgc_domain *domain = to_imx_pgc_domain(genpd); -	u32 reg_val; +	u32 reg_val, pgc;  	int ret;  	ret = pm_runtime_get_sync(domain->dev); @@ -244,6 +245,8 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd)  		goto out_regulator_disable;  	} +	reset_control_assert(domain->reset); +  	if (domain->bits.pxx) {  		/* request the domain to power up */  		regmap_update_bits(domain->regmap, GPC_PU_PGC_SW_PUP_REQ, @@ -262,12 +265,12 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd)  		}  		/* disable power control */ -		regmap_clear_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc), -				  GPC_PGC_CTRL_PCR); +		for_each_set_bit(pgc, &domain->pgc, 32) { +			regmap_clear_bits(domain->regmap, GPC_PGC_CTRL(pgc), +					  GPC_PGC_CTRL_PCR); +		}  	} -	reset_control_assert(domain->reset); -  	/* delay for reset to propagate */  	udelay(5); @@ -293,7 +296,8 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd)  	}  	/* Disable reset clocks for all devices in the domain */ -	clk_bulk_disable_unprepare(domain->num_clks, domain->clks); +	if (!domain->keep_clocks) +		clk_bulk_disable_unprepare(domain->num_clks, domain->clks);  	return 0; @@ -311,14 +315,16 @@ out_put_pm:  static int imx_pgc_power_down(struct generic_pm_domain *genpd)  {  	struct imx_pgc_domain *domain = to_imx_pgc_domain(genpd); -	u32 reg_val; +	u32 reg_val, pgc;  	int ret;  	/* Enable reset clocks for all devices in the domain */ -	ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks); -	if (ret) { -		dev_err(domain->dev, "failed to enable reset clocks\n"); -		return ret; +	if (!domain->keep_clocks) { +		ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks); +		if (ret) { +			dev_err(domain->dev, "failed to enable reset clocks\n"); +			return ret; +		}  	}  	/* request the ADB400 to power down */ @@ -338,8 +344,10 @@ static int imx_pgc_power_down(struct generic_pm_domain *genpd)  	if (domain->bits.pxx) {  		/* enable power control */ -		regmap_update_bits(domain->regmap, GPC_PGC_CTRL(domain->pgc), -				   GPC_PGC_CTRL_PCR, GPC_PGC_CTRL_PCR); +		for_each_set_bit(pgc, &domain->pgc, 32) { +			regmap_update_bits(domain->regmap, GPC_PGC_CTRL(pgc), +					   GPC_PGC_CTRL_PCR, GPC_PGC_CTRL_PCR); +		}  		/* request the domain to power down */  		regmap_update_bits(domain->regmap, GPC_PU_PGC_SW_PDN_REQ, @@ -389,7 +397,7 @@ static const struct imx_pgc_domain imx7_pgc_domains[] = {  			.map = IMX7_MIPI_PHY_A_CORE_DOMAIN,  		},  		.voltage   = 1000000, -		.pgc	   = IMX7_PGC_MIPI, +		.pgc	   = BIT(IMX7_PGC_MIPI),  	},  	[IMX7_POWER_DOMAIN_PCIE_PHY] = { @@ -401,7 +409,7 @@ static const struct imx_pgc_domain imx7_pgc_domains[] = {  			.map = IMX7_PCIE_PHY_A_CORE_DOMAIN,  		},  		.voltage   = 1000000, -		.pgc	   = IMX7_PGC_PCIE, +		.pgc	   = BIT(IMX7_PGC_PCIE),  	},  	[IMX7_POWER_DOMAIN_USB_HSIC_PHY] = { @@ -413,7 +421,7 @@ static const struct imx_pgc_domain imx7_pgc_domains[] = {  			.map = IMX7_USB_HSIC_PHY_A_CORE_DOMAIN,  		},  		.voltage   = 1200000, -		.pgc	   = IMX7_PGC_USB_HSIC, +		.pgc	   = BIT(IMX7_PGC_USB_HSIC),  	},  }; @@ -448,7 +456,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {  			.pxx = IMX8M_MIPI_SW_Pxx_REQ,  			.map = IMX8M_MIPI_A53_DOMAIN,  		}, -		.pgc	   = IMX8M_PGC_MIPI, +		.pgc	   = BIT(IMX8M_PGC_MIPI),  	},  	[IMX8M_POWER_DOMAIN_PCIE1] = { @@ -459,7 +467,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {  			.pxx = IMX8M_PCIE1_SW_Pxx_REQ,  			.map = IMX8M_PCIE1_A53_DOMAIN,  		}, -		.pgc   = IMX8M_PGC_PCIE1, +		.pgc   = BIT(IMX8M_PGC_PCIE1),  	},  	[IMX8M_POWER_DOMAIN_USB_OTG1] = { @@ -470,7 +478,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {  			.pxx = IMX8M_OTG1_SW_Pxx_REQ,  			.map = IMX8M_OTG1_A53_DOMAIN,  		}, -		.pgc   = IMX8M_PGC_OTG1, +		.pgc   = BIT(IMX8M_PGC_OTG1),  	},  	[IMX8M_POWER_DOMAIN_USB_OTG2] = { @@ -481,7 +489,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {  			.pxx = IMX8M_OTG2_SW_Pxx_REQ,  			.map = IMX8M_OTG2_A53_DOMAIN,  		}, -		.pgc   = IMX8M_PGC_OTG2, +		.pgc   = BIT(IMX8M_PGC_OTG2),  	},  	[IMX8M_POWER_DOMAIN_DDR1] = { @@ -492,7 +500,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {  			.pxx = IMX8M_DDR1_SW_Pxx_REQ,  			.map = IMX8M_DDR2_A53_DOMAIN,  		}, -		.pgc   = IMX8M_PGC_DDR1, +		.pgc   = BIT(IMX8M_PGC_DDR1),  	},  	[IMX8M_POWER_DOMAIN_GPU] = { @@ -505,7 +513,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {  			.hskreq = IMX8M_GPU_HSK_PWRDNREQN,  			.hskack = IMX8M_GPU_HSK_PWRDNACKN,  		}, -		.pgc   = IMX8M_PGC_GPU, +		.pgc   = BIT(IMX8M_PGC_GPU),  	},  	[IMX8M_POWER_DOMAIN_VPU] = { @@ -518,7 +526,8 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {  			.hskreq = IMX8M_VPU_HSK_PWRDNREQN,  			.hskack = IMX8M_VPU_HSK_PWRDNACKN,  		}, -		.pgc   = IMX8M_PGC_VPU, +		.pgc   = BIT(IMX8M_PGC_VPU), +		.keep_clocks = true,  	},  	[IMX8M_POWER_DOMAIN_DISP] = { @@ -531,7 +540,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {  			.hskreq = IMX8M_DISP_HSK_PWRDNREQN,  			.hskack = IMX8M_DISP_HSK_PWRDNACKN,  		}, -		.pgc   = IMX8M_PGC_DISP, +		.pgc   = BIT(IMX8M_PGC_DISP),  	},  	[IMX8M_POWER_DOMAIN_MIPI_CSI1] = { @@ -542,7 +551,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {  			.pxx = IMX8M_MIPI_CSI1_SW_Pxx_REQ,  			.map = IMX8M_MIPI_CSI1_A53_DOMAIN,  		}, -		.pgc   = IMX8M_PGC_MIPI_CSI1, +		.pgc   = BIT(IMX8M_PGC_MIPI_CSI1),  	},  	[IMX8M_POWER_DOMAIN_MIPI_CSI2] = { @@ -553,7 +562,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {  			.pxx = IMX8M_MIPI_CSI2_SW_Pxx_REQ,  			.map = IMX8M_MIPI_CSI2_A53_DOMAIN,  		}, -		.pgc   = IMX8M_PGC_MIPI_CSI2, +		.pgc   = BIT(IMX8M_PGC_MIPI_CSI2),  	},  	[IMX8M_POWER_DOMAIN_PCIE2] = { @@ -564,7 +573,7 @@ static const struct imx_pgc_domain imx8m_pgc_domains[] = {  			.pxx = IMX8M_PCIE2_SW_Pxx_REQ,  			.map = IMX8M_PCIE2_A53_DOMAIN,  		}, -		.pgc   = IMX8M_PGC_PCIE2, +		.pgc   = BIT(IMX8M_PGC_PCIE2),  	},  }; @@ -617,6 +626,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {  			.hskreq = IMX8MM_HSIO_HSK_PWRDNREQN,  			.hskack = IMX8MM_HSIO_HSK_PWRDNACKN,  		}, +		.keep_clocks = true,  	},  	[IMX8MM_POWER_DOMAIN_PCIE] = { @@ -627,7 +637,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {  			.pxx = IMX8MM_PCIE_SW_Pxx_REQ,  			.map = IMX8MM_PCIE_A53_DOMAIN,  		}, -		.pgc   = IMX8MM_PGC_PCIE, +		.pgc   = BIT(IMX8MM_PGC_PCIE),  	},  	[IMX8MM_POWER_DOMAIN_OTG1] = { @@ -638,7 +648,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {  			.pxx = IMX8MM_OTG1_SW_Pxx_REQ,  			.map = IMX8MM_OTG1_A53_DOMAIN,  		}, -		.pgc   = IMX8MM_PGC_OTG1, +		.pgc   = BIT(IMX8MM_PGC_OTG1),  	},  	[IMX8MM_POWER_DOMAIN_OTG2] = { @@ -649,7 +659,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {  			.pxx = IMX8MM_OTG2_SW_Pxx_REQ,  			.map = IMX8MM_OTG2_A53_DOMAIN,  		}, -		.pgc   = IMX8MM_PGC_OTG2, +		.pgc   = BIT(IMX8MM_PGC_OTG2),  	},  	[IMX8MM_POWER_DOMAIN_GPUMIX] = { @@ -662,7 +672,8 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {  			.hskreq = IMX8MM_GPUMIX_HSK_PWRDNREQN,  			.hskack = IMX8MM_GPUMIX_HSK_PWRDNACKN,  		}, -		.pgc   = IMX8MM_PGC_GPUMIX, +		.pgc   = BIT(IMX8MM_PGC_GPUMIX), +		.keep_clocks = true,  	},  	[IMX8MM_POWER_DOMAIN_GPU] = { @@ -675,7 +686,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {  			.hskreq = IMX8MM_GPU_HSK_PWRDNREQN,  			.hskack = IMX8MM_GPU_HSK_PWRDNACKN,  		}, -		.pgc   = IMX8MM_PGC_GPU2D, +		.pgc   = BIT(IMX8MM_PGC_GPU2D) | BIT(IMX8MM_PGC_GPU3D),  	},  	[IMX8MM_POWER_DOMAIN_VPUMIX] = { @@ -688,7 +699,8 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {  			.hskreq = IMX8MM_VPUMIX_HSK_PWRDNREQN,  			.hskack = IMX8MM_VPUMIX_HSK_PWRDNACKN,  		}, -		.pgc   = IMX8MM_PGC_VPUMIX, +		.pgc   = BIT(IMX8MM_PGC_VPUMIX), +		.keep_clocks = true,  	},  	[IMX8MM_POWER_DOMAIN_VPUG1] = { @@ -699,7 +711,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {  			.pxx = IMX8MM_VPUG1_SW_Pxx_REQ,  			.map = IMX8MM_VPUG1_A53_DOMAIN,  		}, -		.pgc   = IMX8MM_PGC_VPUG1, +		.pgc   = BIT(IMX8MM_PGC_VPUG1),  	},  	[IMX8MM_POWER_DOMAIN_VPUG2] = { @@ -710,7 +722,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {  			.pxx = IMX8MM_VPUG2_SW_Pxx_REQ,  			.map = IMX8MM_VPUG2_A53_DOMAIN,  		}, -		.pgc   = IMX8MM_PGC_VPUG2, +		.pgc   = BIT(IMX8MM_PGC_VPUG2),  	},  	[IMX8MM_POWER_DOMAIN_VPUH1] = { @@ -721,7 +733,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {  			.pxx = IMX8MM_VPUH1_SW_Pxx_REQ,  			.map = IMX8MM_VPUH1_A53_DOMAIN,  		}, -		.pgc   = IMX8MM_PGC_VPUH1, +		.pgc   = BIT(IMX8MM_PGC_VPUH1),  	},  	[IMX8MM_POWER_DOMAIN_DISPMIX] = { @@ -734,7 +746,8 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {  			.hskreq = IMX8MM_DISPMIX_HSK_PWRDNREQN,  			.hskack = IMX8MM_DISPMIX_HSK_PWRDNACKN,  		}, -		.pgc   = IMX8MM_PGC_DISPMIX, +		.pgc   = BIT(IMX8MM_PGC_DISPMIX), +		.keep_clocks = true,  	},  	[IMX8MM_POWER_DOMAIN_MIPI] = { @@ -745,7 +758,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = {  			.pxx = IMX8MM_MIPI_SW_Pxx_REQ,  			.map = IMX8MM_MIPI_A53_DOMAIN,  		}, -		.pgc   = IMX8MM_PGC_MIPI, +		.pgc   = BIT(IMX8MM_PGC_MIPI),  	},  }; @@ -802,6 +815,7 @@ static const struct imx_pgc_domain imx8mn_pgc_domains[] = {  			.hskreq = IMX8MN_HSIO_HSK_PWRDNREQN,  			.hskack = IMX8MN_HSIO_HSK_PWRDNACKN,  		}, +		.keep_clocks = true,  	},  	[IMX8MN_POWER_DOMAIN_OTG1] = { @@ -812,7 +826,7 @@ static const struct imx_pgc_domain imx8mn_pgc_domains[] = {  			.pxx = IMX8MN_OTG1_SW_Pxx_REQ,  			.map = IMX8MN_OTG1_A53_DOMAIN,  		}, -		.pgc   = IMX8MN_PGC_OTG1, +		.pgc   = BIT(IMX8MN_PGC_OTG1),  	},  	[IMX8MN_POWER_DOMAIN_GPUMIX] = { @@ -825,7 +839,7 @@ static const struct imx_pgc_domain imx8mn_pgc_domains[] = {  			.hskreq = IMX8MN_GPUMIX_HSK_PWRDNREQN,  			.hskack = IMX8MN_GPUMIX_HSK_PWRDNACKN,  		}, -		.pgc   = IMX8MN_PGC_GPUMIX, +		.pgc   = BIT(IMX8MN_PGC_GPUMIX),  	},  }; @@ -894,6 +908,10 @@ static int imx_pgc_domain_probe(struct platform_device *pdev)  		goto out_domain_unmap;  	} +	if (IS_ENABLED(CONFIG_LOCKDEP) && +	    of_property_read_bool(domain->dev->of_node, "power-domains")) +		lockdep_set_subclass(&domain->genpd.mlock, 1); +  	ret = of_genpd_add_provider_simple(domain->dev->of_node,  					   &domain->genpd);  	if (ret) { @@ -930,6 +948,36 @@ static int imx_pgc_domain_remove(struct platform_device *pdev)  	return 0;  } +#ifdef CONFIG_PM_SLEEP +static int imx_pgc_domain_suspend(struct device *dev) +{ +	int ret; + +	/* +	 * This may look strange, but is done so the generic PM_SLEEP code +	 * can power down our domain and more importantly power it up again +	 * after resume, without tripping over our usage of runtime PM to +	 * power up/down the nested domains. +	 */ +	ret = pm_runtime_get_sync(dev); +	if (ret < 0) { +		pm_runtime_put_noidle(dev); +		return ret; +	} + +	return 0; +} + +static int imx_pgc_domain_resume(struct device *dev) +{ +	return pm_runtime_put(dev); +} +#endif + +static const struct dev_pm_ops imx_pgc_domain_pm_ops = { +	SET_SYSTEM_SLEEP_PM_OPS(imx_pgc_domain_suspend, imx_pgc_domain_resume) +}; +  static const struct platform_device_id imx_pgc_domain_id[] = {  	{ "imx-pgc-domain", },  	{ }, @@ -938,6 +986,7 @@ static const struct platform_device_id imx_pgc_domain_id[] = {  static struct platform_driver imx_pgc_domain_driver = {  	.driver = {  		.name = "imx-pgc", +		.pm = &imx_pgc_domain_pm_ops,  	},  	.probe    = imx_pgc_domain_probe,  	.remove   = imx_pgc_domain_remove, @@ -986,6 +1035,9 @@ static int imx_gpcv2_probe(struct platform_device *pdev)  		struct imx_pgc_domain *domain;  		u32 domain_index; +		if (!of_device_is_available(np)) +			continue; +  		ret = of_property_read_u32(np, "reg", &domain_index);  		if (ret) {  			dev_err(dev, "Failed to read 'reg' property\n");  |