[PATCH 4/8] clk: qcom: add support for power domains uclass

Konrad Dybcio konrad.dybcio at linaro.org
Sat Mar 2 01:05:51 CET 2024


On 29.02.2024 15:21, Volodymyr Babchuk wrote:
> Now sub-drivers for particular SoCs can register them as power domain
> drivers. This is needed for upcoming SM8150 support, because it needs
> to power up the Ethernet module.
> 
> Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk at epam.com>
> ---
> 
>  drivers/clk/qcom/clock-qcom.c | 93 ++++++++++++++++++++++++++++++++++-
>  drivers/clk/qcom/clock-qcom.h |  6 +++
>  2 files changed, 98 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/clk/qcom/clock-qcom.c b/drivers/clk/qcom/clock-qcom.c
> index 729d190c54..986b8e4da4 100644
> --- a/drivers/clk/qcom/clock-qcom.c
> +++ b/drivers/clk/qcom/clock-qcom.c
> @@ -23,6 +23,7 @@
>  #include <linux/delay.h>
>  #include <linux/bitops.h>
>  #include <reset-uclass.h>
> +#include <power-domain-uclass.h>
>  
>  #include "clock-qcom.h"
>  
> @@ -30,6 +31,11 @@
>  #define CBCR_BRANCH_ENABLE_BIT  BIT(0)
>  #define CBCR_BRANCH_OFF_BIT     BIT(31)
>  
> +#define GDSC_POWER_UP_COMPLETE		BIT(16)
> +#define GDSC_POWER_DOWN_COMPLETE	BIT(15)

Please keep things sorted by bit index for bitfields and register offset
for registers

> +#define CFG_GDSCR_OFFSET		0x4
> +#define PWR_ON_MASK			BIT(31)
> +
>  /* Enable clock controlled by CBC soft macro */
>  void clk_enable_cbc(phys_addr_t cbcr)
>  {
> @@ -223,7 +229,7 @@ U_BOOT_DRIVER(qcom_clk) = {
>  int qcom_cc_bind(struct udevice *parent)
>  {
>  	struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(parent);
> -	struct udevice *clkdev, *rstdev;
> +	struct udevice *clkdev, *rstdev, *pwrdev;
>  	struct driver *drv;
>  	int ret;
>  
> @@ -253,6 +259,20 @@ int qcom_cc_bind(struct udevice *parent)
>  	if (ret)
>  		device_unbind(clkdev);
>  
> +	if (!data->power_domains)
> +		return ret;
> +
> +	/* Get a handle to the common power domain handler */
> +	drv = lists_driver_lookup_name("qcom_power");
> +	if (!drv)
> +		return -ENOENT;
> +
> +	/* Register the power domain controller */
> +	ret = device_bind_with_driver_data(parent, drv, "qcom_power", (ulong)data,
> +					   dev_ofnode(parent), &pwrdev);
> +	if (ret)
> +		device_unbind(pwrdev);
> +
>  	return ret;
>  }
>  
> @@ -306,3 +326,74 @@ U_BOOT_DRIVER(qcom_reset) = {
>  	.ops = &qcom_reset_ops,
>  	.probe = qcom_reset_probe,
>  };
> +
> +static int qcom_power_set(struct power_domain *pwr, bool on)
> +{
> +	struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(pwr->dev);
> +	void __iomem *base = dev_get_priv(pwr->dev);
> +	const struct qcom_power_map *map;
> +	u32 value;
> +
> +	if (pwr->id >= data->num_power_domains)
> +		return -ENODEV;
> +
> +	map = &data->power_domains[pwr->id];
> +
> +	if (!map->reg)
> +		return -ENODEV;
> +
> +	value = readl(base + map->reg);
> +
> +	if (on)
> +		value &= ~BIT(0);

These magic bits should be #defined.

> +	else
> +		value |= BIT(0);
> +
> +	writel(value, base + map->reg);
> +
> +	/* Wait for power on */
> +	while (true) {

Uhh.. I'm not sure a tight loop is the best idea here, especially since
GDSCs are known to be grumpy and not wanna power on if they're missing
a dependency. I'd say a timeout is definitely in order. 1500ms following
Linux

Konrad


More information about the U-Boot mailing list