Re: [PATCH v2 6/6] clk: samsung: exynos5433: Extract PM support to common ARM64 layer

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 8 Feb 2023 at 17:43, Sam Protsenko <semen.protsenko@xxxxxxxxxx> wrote:
>
> Exynos5433 clock driver implements PM support internally, which might be
> also useful for other Exynos clock drivers. Extract all PM related code
> from clk-exynos5433 to common ARM64 functions.
>
> Tested-by: Marek Szyprowski <m.szyprowski@xxxxxxxxxxx>
> Signed-off-by: Sam Protsenko <semen.protsenko@xxxxxxxxxx>
> ---
> Changes in v2:
>   - Rebased on top of latest soc/for-next tree
>   - Included linux/slab.h for kfree (found by kernel test robot)
>
>  drivers/clk/samsung/clk-exynos-arm64.c | 171 ++++++++++++++++++++++++-
>  drivers/clk/samsung/clk-exynos-arm64.h |   3 +
>  drivers/clk/samsung/clk-exynos5433.c   | 157 +----------------------
>  3 files changed, 175 insertions(+), 156 deletions(-)
>
> diff --git a/drivers/clk/samsung/clk-exynos-arm64.c b/drivers/clk/samsung/clk-exynos-arm64.c
> index 2aa3f0a5644e..7ad7fd353dda 100644
> --- a/drivers/clk/samsung/clk-exynos-arm64.c
> +++ b/drivers/clk/samsung/clk-exynos-arm64.c
> @@ -10,6 +10,9 @@
>   */

Hi Marek,

It just occurred to me that as I'm pulling your code from
clk-exynos5433.c here, I should've probably added you to this file's
author list in the header comment. Does that sound right to you? If
so, I can re-send v3 with fixes.

Also, could you please review this series, if possible? I'm working
right now on PM_DOMAINS support for Exynos850, so along with this
series that would bring the initial PM support for ARM64 Exynos chips.

Thanks!

>  #include <linux/clk.h>
>  #include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/slab.h>
>
>  #include "clk-exynos-arm64.h"
>
> @@ -21,6 +24,19 @@
>  #define GATE_OFF_START         0x2000
>  #define GATE_OFF_END           0x2fff
>
> +struct exynos_arm64_cmu_data {
> +       struct samsung_clk_reg_dump *clk_save;
> +       unsigned int nr_clk_save;
> +       const struct samsung_clk_reg_dump *clk_suspend;
> +       unsigned int nr_clk_suspend;
> +
> +       struct clk *clk;
> +       struct clk **pclks;
> +       int nr_pclks;
> +
> +       struct samsung_clk_provider *ctx;
> +};
> +
>  /**
>   * exynos_arm64_init_clocks - Set clocks initial configuration
>   * @np:                        CMU device tree node with "reg" property (CMU addr)
> @@ -76,10 +92,16 @@ static int __init exynos_arm64_enable_bus_clk(struct device *dev,
>         if (!cmu->clk_name)
>                 return 0;
>
> -       if (dev)
> +       if (dev) {
> +               struct exynos_arm64_cmu_data *data;
> +
>                 parent_clk = clk_get(dev, cmu->clk_name);
> -       else
> +               data = dev_get_drvdata(dev);
> +               if (data)
> +                       data->clk = parent_clk;
> +       } else {
>                 parent_clk = of_clk_get_by_name(np, cmu->clk_name);
> +       }
>
>         if (IS_ERR(parent_clk))
>                 return PTR_ERR(parent_clk);
> @@ -87,6 +109,46 @@ static int __init exynos_arm64_enable_bus_clk(struct device *dev,
>         return clk_prepare_enable(parent_clk);
>  }
>
> +static int __init exynos_arm64_cmu_prepare_pm(struct device *dev,
> +               const struct samsung_cmu_info *cmu)
> +{
> +       struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev);
> +       int i;
> +
> +       data->clk_save = samsung_clk_alloc_reg_dump(cmu->clk_regs,
> +                                                   cmu->nr_clk_regs);
> +       if (!data->clk_save)
> +               return -ENOMEM;
> +
> +       data->nr_clk_save = cmu->nr_clk_regs;
> +       data->clk_suspend = cmu->suspend_regs;
> +       data->nr_clk_suspend = cmu->nr_suspend_regs;
> +       data->nr_pclks = of_clk_get_parent_count(dev->of_node);
> +       if (!data->nr_pclks)
> +               return 0;
> +
> +       data->pclks = devm_kcalloc(dev, sizeof(struct clk *), data->nr_pclks,
> +                                  GFP_KERNEL);
> +       if (!data->pclks) {
> +               kfree(data->clk_save);
> +               return -ENOMEM;
> +       }
> +
> +       for (i = 0; i < data->nr_pclks; i++) {
> +               struct clk *clk = of_clk_get(dev->of_node, i);
> +
> +               if (IS_ERR(clk)) {
> +                       kfree(data->clk_save);
> +                       while (--i >= 0)
> +                               clk_put(data->pclks[i]);
> +                       return PTR_ERR(clk);
> +               }
> +               data->pclks[i] = clk;
> +       }
> +
> +       return 0;
> +}
> +
>  /**
>   * exynos_arm64_register_cmu - Register specified Exynos CMU domain
>   * @dev:       Device object; may be NULL if this function is not being
> @@ -111,3 +173,108 @@ void __init exynos_arm64_register_cmu(struct device *dev,
>         exynos_arm64_init_clocks(np, cmu->clk_regs, cmu->nr_clk_regs);
>         samsung_cmu_register_one(np, cmu);
>  }
> +
> +/**
> + * exynos_arm64_register_cmu_pm - Register Exynos CMU domain with PM support
> + *
> + * @pdev:      Platform device object
> + * @set_manual:        If true, set gate clocks to manual mode
> + *
> + * It's a version of exynos_arm64_register_cmu() with PM support. Should be
> + * called from probe function of platform driver.
> + *
> + * Return: 0 on success, or negative error code on error.
> + */
> +int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev,
> +                                       bool set_manual)
> +{
> +       const struct samsung_cmu_info *cmu;
> +       struct device *dev = &pdev->dev;
> +       struct device_node *np = dev->of_node;
> +       struct exynos_arm64_cmu_data *data;
> +       void __iomem *reg_base;
> +       int ret;
> +
> +       cmu = of_device_get_match_data(dev);
> +
> +       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> +       if (!data)
> +               return -ENOMEM;
> +
> +       platform_set_drvdata(pdev, data);
> +
> +       ret = exynos_arm64_cmu_prepare_pm(dev, cmu);
> +       if (ret)
> +               return ret;
> +
> +       ret = exynos_arm64_enable_bus_clk(dev, NULL, cmu);
> +       if (ret)
> +               return ret;
> +
> +       if (set_manual)
> +               exynos_arm64_init_clocks(np, cmu->clk_regs, cmu->nr_clk_regs);
> +
> +       reg_base = devm_platform_ioremap_resource(pdev, 0);
> +       if (IS_ERR(reg_base))
> +               return PTR_ERR(reg_base);
> +
> +       data->ctx = samsung_clk_init(dev, reg_base, cmu->nr_clk_ids);
> +
> +       /*
> +        * Enable runtime PM here to allow the clock core using runtime PM
> +        * for the registered clocks. Additionally, we increase the runtime
> +        * PM usage count before registering the clocks, to prevent the
> +        * clock core from runtime suspending the device.
> +        */
> +       pm_runtime_get_noresume(dev);
> +       pm_runtime_set_active(dev);
> +       pm_runtime_enable(dev);
> +
> +       samsung_cmu_register_clocks(data->ctx, cmu);
> +       samsung_clk_of_add_provider(dev->of_node, data->ctx);
> +       pm_runtime_put_sync(dev);
> +
> +       return 0;
> +}
> +
> +int exynos_arm64_cmu_suspend(struct device *dev)
> +{
> +       struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev);
> +       int i;
> +
> +       samsung_clk_save(data->ctx->reg_base, data->clk_save,
> +                        data->nr_clk_save);
> +
> +       for (i = 0; i < data->nr_pclks; i++)
> +               clk_prepare_enable(data->pclks[i]);
> +
> +       /* For suspend some registers have to be set to certain values */
> +       samsung_clk_restore(data->ctx->reg_base, data->clk_suspend,
> +                           data->nr_clk_suspend);
> +
> +       for (i = 0; i < data->nr_pclks; i++)
> +               clk_disable_unprepare(data->pclks[i]);
> +
> +       clk_disable_unprepare(data->clk);
> +
> +       return 0;
> +}
> +
> +int exynos_arm64_cmu_resume(struct device *dev)
> +{
> +       struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev);
> +       int i;
> +
> +       clk_prepare_enable(data->clk);
> +
> +       for (i = 0; i < data->nr_pclks; i++)
> +               clk_prepare_enable(data->pclks[i]);
> +
> +       samsung_clk_restore(data->ctx->reg_base, data->clk_save,
> +                           data->nr_clk_save);
> +
> +       for (i = 0; i < data->nr_pclks; i++)
> +               clk_disable_unprepare(data->pclks[i]);
> +
> +       return 0;
> +}
> diff --git a/drivers/clk/samsung/clk-exynos-arm64.h b/drivers/clk/samsung/clk-exynos-arm64.h
> index 0dd174693935..969979e714bc 100644
> --- a/drivers/clk/samsung/clk-exynos-arm64.h
> +++ b/drivers/clk/samsung/clk-exynos-arm64.h
> @@ -16,5 +16,8 @@
>
>  void exynos_arm64_register_cmu(struct device *dev,
>                 struct device_node *np, const struct samsung_cmu_info *cmu);
> +int exynos_arm64_register_cmu_pm(struct platform_device *pdev, bool set_manual);
> +int exynos_arm64_cmu_suspend(struct device *dev);
> +int exynos_arm64_cmu_resume(struct device *dev);
>
>  #endif /* __CLK_EXYNOS_ARM64_H */
> diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c
> index eb72bf2aaee8..ed43233649ae 100644
> --- a/drivers/clk/samsung/clk-exynos5433.c
> +++ b/drivers/clk/samsung/clk-exynos5433.c
> @@ -10,7 +10,6 @@
>  #include <linux/clk-provider.h>
>  #include <linux/of.h>
>  #include <linux/of_address.h>
> -#include <linux/of_device.h>
>  #include <linux/platform_device.h>
>  #include <linux/pm_runtime.h>
>  #include <linux/slab.h>
> @@ -19,6 +18,7 @@
>
>  #include "clk.h"
>  #include "clk-cpu.h"
> +#include "clk-exynos-arm64.h"
>  #include "clk-pll.h"
>
>  /*
> @@ -5478,160 +5478,9 @@ static const struct samsung_cmu_info imem_cmu_info __initconst = {
>         .clk_name               = "aclk_imem_200",
>  };
>
> -struct exynos5433_cmu_data {
> -       struct samsung_clk_reg_dump *clk_save;
> -       unsigned int nr_clk_save;
> -       const struct samsung_clk_reg_dump *clk_suspend;
> -       unsigned int nr_clk_suspend;
> -
> -       struct clk *clk;
> -       struct clk **pclks;
> -       int nr_pclks;
> -
> -       /* must be the last entry */
> -       struct samsung_clk_provider ctx;
> -};
> -
> -static int __maybe_unused exynos5433_cmu_suspend(struct device *dev)
> -{
> -       struct exynos5433_cmu_data *data = dev_get_drvdata(dev);
> -       int i;
> -
> -       samsung_clk_save(data->ctx.reg_base, data->clk_save,
> -                        data->nr_clk_save);
> -
> -       for (i = 0; i < data->nr_pclks; i++)
> -               clk_prepare_enable(data->pclks[i]);
> -
> -       /* for suspend some registers have to be set to certain values */
> -       samsung_clk_restore(data->ctx.reg_base, data->clk_suspend,
> -                           data->nr_clk_suspend);
> -
> -       for (i = 0; i < data->nr_pclks; i++)
> -               clk_disable_unprepare(data->pclks[i]);
> -
> -       clk_disable_unprepare(data->clk);
> -
> -       return 0;
> -}
> -
> -static int __maybe_unused exynos5433_cmu_resume(struct device *dev)
> -{
> -       struct exynos5433_cmu_data *data = dev_get_drvdata(dev);
> -       int i;
> -
> -       clk_prepare_enable(data->clk);
> -
> -       for (i = 0; i < data->nr_pclks; i++)
> -               clk_prepare_enable(data->pclks[i]);
> -
> -       samsung_clk_restore(data->ctx.reg_base, data->clk_save,
> -                           data->nr_clk_save);
> -
> -       for (i = 0; i < data->nr_pclks; i++)
> -               clk_disable_unprepare(data->pclks[i]);
> -
> -       return 0;
> -}
> -
>  static int __init exynos5433_cmu_probe(struct platform_device *pdev)
>  {
> -       const struct samsung_cmu_info *info;
> -       struct exynos5433_cmu_data *data;
> -       struct samsung_clk_provider *ctx;
> -       struct device *dev = &pdev->dev;
> -       void __iomem *reg_base;
> -       int i;
> -
> -       info = of_device_get_match_data(dev);
> -
> -       data = devm_kzalloc(dev,
> -                           struct_size(data, ctx.clk_data.hws, info->nr_clk_ids),
> -                           GFP_KERNEL);
> -       if (!data)
> -               return -ENOMEM;
> -       ctx = &data->ctx;
> -
> -       reg_base = devm_platform_ioremap_resource(pdev, 0);
> -       if (IS_ERR(reg_base))
> -               return PTR_ERR(reg_base);
> -
> -       for (i = 0; i < info->nr_clk_ids; ++i)
> -               ctx->clk_data.hws[i] = ERR_PTR(-ENOENT);
> -
> -       ctx->clk_data.num = info->nr_clk_ids;
> -       ctx->reg_base = reg_base;
> -       ctx->dev = dev;
> -       spin_lock_init(&ctx->lock);
> -
> -       data->clk_save = samsung_clk_alloc_reg_dump(info->clk_regs,
> -                                                   info->nr_clk_regs);
> -       if (!data->clk_save)
> -               return -ENOMEM;
> -       data->nr_clk_save = info->nr_clk_regs;
> -       data->clk_suspend = info->suspend_regs;
> -       data->nr_clk_suspend = info->nr_suspend_regs;
> -       data->nr_pclks = of_clk_get_parent_count(dev->of_node);
> -
> -       if (data->nr_pclks > 0) {
> -               data->pclks = devm_kcalloc(dev, sizeof(struct clk *),
> -                                          data->nr_pclks, GFP_KERNEL);
> -               if (!data->pclks) {
> -                       kfree(data->clk_save);
> -                       return -ENOMEM;
> -               }
> -               for (i = 0; i < data->nr_pclks; i++) {
> -                       struct clk *clk = of_clk_get(dev->of_node, i);
> -
> -                       if (IS_ERR(clk)) {
> -                               kfree(data->clk_save);
> -                               while (--i >= 0)
> -                                       clk_put(data->pclks[i]);
> -                               return PTR_ERR(clk);
> -                       }
> -                       data->pclks[i] = clk;
> -               }
> -       }
> -
> -       if (info->clk_name)
> -               data->clk = clk_get(dev, info->clk_name);
> -       clk_prepare_enable(data->clk);
> -
> -       platform_set_drvdata(pdev, data);
> -
> -       /*
> -        * Enable runtime PM here to allow the clock core using runtime PM
> -        * for the registered clocks. Additionally, we increase the runtime
> -        * PM usage count before registering the clocks, to prevent the
> -        * clock core from runtime suspending the device.
> -        */
> -       pm_runtime_get_noresume(dev);
> -       pm_runtime_set_active(dev);
> -       pm_runtime_enable(dev);
> -
> -       if (info->pll_clks)
> -               samsung_clk_register_pll(ctx, info->pll_clks,
> -                                        info->nr_pll_clks);
> -       if (info->mux_clks)
> -               samsung_clk_register_mux(ctx, info->mux_clks,
> -                                        info->nr_mux_clks);
> -       if (info->div_clks)
> -               samsung_clk_register_div(ctx, info->div_clks,
> -                                        info->nr_div_clks);
> -       if (info->gate_clks)
> -               samsung_clk_register_gate(ctx, info->gate_clks,
> -                                         info->nr_gate_clks);
> -       if (info->fixed_clks)
> -               samsung_clk_register_fixed_rate(ctx, info->fixed_clks,
> -                                               info->nr_fixed_clks);
> -       if (info->fixed_factor_clks)
> -               samsung_clk_register_fixed_factor(ctx, info->fixed_factor_clks,
> -                                                 info->nr_fixed_factor_clks);
> -
> -       samsung_clk_of_add_provider(dev->of_node, ctx);
> -       pm_runtime_put_sync(dev);
> -
> -       return 0;
> +       return exynos_arm64_register_cmu_pm(pdev, false);
>  }
>
>  static const struct of_device_id exynos5433_cmu_of_match[] = {
> @@ -5679,7 +5528,7 @@ static const struct of_device_id exynos5433_cmu_of_match[] = {
>  };
>
>  static const struct dev_pm_ops exynos5433_cmu_pm_ops = {
> -       SET_RUNTIME_PM_OPS(exynos5433_cmu_suspend, exynos5433_cmu_resume,
> +       SET_RUNTIME_PM_OPS(exynos_arm64_cmu_suspend, exynos_arm64_cmu_resume,
>                            NULL)
>         SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
>                                      pm_runtime_force_resume)
> --
> 2.39.1
>



[Index of Archives]     [Linux SoC Development]     [Linux Rockchip Development]     [Linux for Synopsys ARC Processors]    
  • [Linux on Unisoc (RDA Micro) SoCs]     [Linux Actions SoC]     [Linux USB Development]     [Video for Linux]     [Linux Audio Users]     [Linux SCSI]     [Yosemite News]

  •   Powered by Linux