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_babc...@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

Reply via email to