Skip to content

Commit

Permalink
Merge tag 'samsung-clk-6.4' of https://git.kernel.org/pub/scm/linux/k…
Browse files Browse the repository at this point in the history
…ernel/git/krzk/linux into clk-samsung

Pull Samsung SoC clk drivers updates from Krzysztof Kozlowski:

 - Exynos850: Add CMU_G3D clock controller for the Mali GPU.  This
   brings new PLLs and few cleanups/simplifications in core Exynos clock
   controller code, so they can be easier re-used in Exynos850 clock
   controller driver.
   New CMU_G3D clock controller needs Devicetree bindings header changes
   with clock indices which are pulled from Samsung SoC repository.

 - Extract Exynos5433 (ARM64) clock controller power management code to
   common driver parts, so later it can be re-used by other Exynos clock
   controller drivers.  This only prepares for such re-usage, which is
   expected to come later for Exynos850.

 - Exynos850: make PMU_ALIVE_PCLK clock critical, because it is needed
   for core block - Power Management Unit.

 - Cleanup: remove() callback returns void.

* tag 'samsung-clk-6.4' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux:
  clk: samsung: exynos850: Make PMU_ALIVE_PCLK critical
  clk: samsung: Convert to platform remove callback returning void
  clk: samsung: exynos5433: Extract PM support to common ARM64 layer
  clk: samsung: Extract parent clock enabling to common function
  clk: samsung: Extract clocks registration to common function
  clk: samsung: exynos850: Add AUD and HSI main gate clocks
  clk: samsung: exynos850: Implement CMU_G3D domain
  clk: samsung: clk-pll: Implement pll0818x PLL type
  clk: samsung: Set dev in samsung_clk_init()
  clk: samsung: Don't pass reg_base to samsung_clk_register_pll()
  clk: samsung: Remove np argument from samsung_clk_init()
  dt-bindings: clock: exynos850: Add AUD and HSI main gate clocks
  dt-bindings: clock: exynos850: Add Exynos850 CMU_G3D
  • Loading branch information
bebarino committed Apr 3, 2023
2 parents fe15c26 + babb3e6 commit ef38222
Show file tree
Hide file tree
Showing 18 changed files with 475 additions and 230 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ properties:
- samsung,exynos850-cmu-cmgp
- samsung,exynos850-cmu-core
- samsung,exynos850-cmu-dpu
- samsung,exynos850-cmu-g3d
- samsung,exynos850-cmu-hsi
- samsung,exynos850-cmu-is
- samsung,exynos850-cmu-mfcmscl
Expand Down Expand Up @@ -169,6 +170,24 @@ allOf:
- const: oscclk
- const: dout_dpu

- if:
properties:
compatible:
contains:
const: samsung,exynos850-cmu-g3d

then:
properties:
clocks:
items:
- description: External reference clock (26 MHz)
- description: G3D clock (from CMU_TOP)

clock-names:
items:
- const: oscclk
- const: dout_g3d_switch

- if:
properties:
compatible:
Expand Down
229 changes: 213 additions & 16 deletions drivers/clk/samsung/clk-exynos-arm64.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
*/
#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"

Expand All @@ -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)
Expand Down Expand Up @@ -56,6 +72,83 @@ static void __init exynos_arm64_init_clocks(struct device_node *np,
iounmap(reg_base);
}

/**
* exynos_arm64_enable_bus_clk - Enable parent clock of specified CMU
*
* @dev: Device object; may be NULL if this function is not being
* called from platform driver probe function
* @np: CMU device tree node
* @cmu: CMU data
*
* Keep CMU parent clock running (needed for CMU registers access).
*
* Return: 0 on success or a negative error code on failure.
*/
static int __init exynos_arm64_enable_bus_clk(struct device *dev,
struct device_node *np, const struct samsung_cmu_info *cmu)
{
struct clk *parent_clk;

if (!cmu->clk_name)
return 0;

if (dev) {
struct exynos_arm64_cmu_data *data;

parent_clk = clk_get(dev, cmu->clk_name);
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);

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
Expand All @@ -72,23 +165,127 @@ static void __init exynos_arm64_init_clocks(struct device_node *np,
void __init exynos_arm64_register_cmu(struct device *dev,
struct device_node *np, const struct samsung_cmu_info *cmu)
{
/* Keep CMU parent clock running (needed for CMU registers access) */
if (cmu->clk_name) {
struct clk *parent_clk;

if (dev)
parent_clk = clk_get(dev, cmu->clk_name);
else
parent_clk = of_clk_get_by_name(np, cmu->clk_name);

if (IS_ERR(parent_clk)) {
pr_err("%s: could not find bus clock %s; err = %ld\n",
__func__, cmu->clk_name, PTR_ERR(parent_clk));
} else {
clk_prepare_enable(parent_clk);
}
}
int err;

/*
* Try to boot even if the parent clock enablement fails, as it might be
* already enabled by bootloader.
*/
err = exynos_arm64_enable_bus_clk(dev, np, cmu);
if (err)
pr_err("%s: could not enable bus clock %s; err = %d\n",
__func__, cmu->clk_name, err);

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;

/*
* Try to boot even if the parent clock enablement fails, as it might be
* already enabled by bootloader.
*/
ret = exynos_arm64_enable_bus_clk(dev, NULL, cmu);
if (ret)
dev_err(dev, "%s: could not enable bus clock %s; err = %d\n",
__func__, cmu->clk_name, 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;
}
3 changes: 3 additions & 0 deletions drivers/clk/samsung/clk-exynos-arm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
6 changes: 2 additions & 4 deletions drivers/clk/samsung/clk-exynos-audss.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
return ret;
}

static int exynos_audss_clk_remove(struct platform_device *pdev)
static void exynos_audss_clk_remove(struct platform_device *pdev)
{
of_clk_del_provider(pdev->dev.of_node);

Expand All @@ -277,8 +277,6 @@ static int exynos_audss_clk_remove(struct platform_device *pdev)

if (!IS_ERR(epll))
clk_disable_unprepare(epll);

return 0;
}

static const struct dev_pm_ops exynos_audss_clk_pm_ops = {
Expand All @@ -295,7 +293,7 @@ static struct platform_driver exynos_audss_clk_driver = {
.pm = &exynos_audss_clk_pm_ops,
},
.probe = exynos_audss_clk_probe,
.remove = exynos_audss_clk_remove,
.remove_new = exynos_audss_clk_remove,
};

module_platform_driver(exynos_audss_clk_driver);
Expand Down
6 changes: 2 additions & 4 deletions drivers/clk/samsung/clk-exynos-clkout.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,15 +196,13 @@ static int exynos_clkout_probe(struct platform_device *pdev)
return ret;
}

static int exynos_clkout_remove(struct platform_device *pdev)
static void exynos_clkout_remove(struct platform_device *pdev)
{
struct exynos_clkout *clkout = platform_get_drvdata(pdev);

of_clk_del_provider(clkout->np);
clk_hw_unregister(clkout->data.hws[0]);
iounmap(clkout->reg);

return 0;
}

static int __maybe_unused exynos_clkout_suspend(struct device *dev)
Expand Down Expand Up @@ -235,7 +233,7 @@ static struct platform_driver exynos_clkout_driver = {
.pm = &exynos_clkout_pm_ops,
},
.probe = exynos_clkout_probe,
.remove = exynos_clkout_remove,
.remove_new = exynos_clkout_remove,
};
module_platform_driver(exynos_clkout_driver);

Expand Down
6 changes: 3 additions & 3 deletions drivers/clk/samsung/clk-exynos4.c
Original file line number Diff line number Diff line change
Expand Up @@ -1251,7 +1251,7 @@ static void __init exynos4_clk_init(struct device_node *np,
if (!reg_base)
panic("%s: failed to map registers\n", __func__);

ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS);
ctx = samsung_clk_init(NULL, reg_base, CLK_NR_CLKS);
hws = ctx->clk_data.hws;

samsung_clk_of_register_fixed_ext(ctx, exynos4_fixed_rate_ext_clks,
Expand All @@ -1276,7 +1276,7 @@ static void __init exynos4_clk_init(struct device_node *np,
exynos4210_vpll_rates;

samsung_clk_register_pll(ctx, exynos4210_plls,
ARRAY_SIZE(exynos4210_plls), reg_base);
ARRAY_SIZE(exynos4210_plls));
} else {
if (clk_hw_get_rate(hws[CLK_FIN_PLL]) == 24000000) {
exynos4x12_plls[apll].rate_table =
Expand All @@ -1288,7 +1288,7 @@ static void __init exynos4_clk_init(struct device_node *np,
}

samsung_clk_register_pll(ctx, exynos4x12_plls,
ARRAY_SIZE(exynos4x12_plls), reg_base);
ARRAY_SIZE(exynos4x12_plls));
}

samsung_clk_register_fixed_rate(ctx, exynos4_fixed_rate_clks,
Expand Down
3 changes: 1 addition & 2 deletions drivers/clk/samsung/clk-exynos4412-isp.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,7 @@ static int __init exynos4x12_isp_clk_probe(struct platform_device *pdev)
if (!exynos4x12_save_isp)
return -ENOMEM;

ctx = samsung_clk_init(np, reg_base, CLK_NR_ISP_CLKS);
ctx->dev = dev;
ctx = samsung_clk_init(dev, reg_base, CLK_NR_ISP_CLKS);

platform_set_drvdata(pdev, ctx);

Expand Down
Loading

0 comments on commit ef38222

Please sign in to comment.