Skip to content

Commit 7fa3708

Browse files
Sam Protsenkokrzk
authored andcommitted
clk: samsung: Implement manual PLL control for ARM64 SoCs
Some ARM64 Exynos chips are capable to control PLL clocks automatically. For those chips, whether the PLL is controlled automatically or manually is chosen in PLL_CON1 register with next bits: [28] ENABLE_AUTOMATIC_CLKGATING [1] MANUAL_PLL_CTRL [0] AUTO_PLL_CTRL The bl2 bootloader sets 0x10000001 value for some PLL_CON1 registers, which means any attempt to control those PLLs manually (e.g. disabling/enabling those PLLs or changing MUX parent clocks) would lead to PLL lock timeout with error message like this: Could not lock PLL ... At the moment, all Samsung clock drivers implement manual clock control. So in order to make it possible to control PLLs, corresponding PLL_CON1 registers should be set to 0x2 first. Some older ARM64 chips don't implement the automatic clock control though. It also might be desirable to configure some PLLs for manual control, while keeping the default configuration for the rest. So it'd convenient to choose this PLL mode for each CMU separately. Introduce .manual_plls field to CMU structure to choose the PLL control mode. Because it'll be initialized with "false" in all existing CMU structures by default, it won't affect any existing clock drivers, allowing for this feature to be enabled gradually when it's needed with no change for the rest of users. In case .manual_plls is set, set PLL_CON1 registers to manual control, akin to what's already done for gate clocks in exynos_arm64_init_clocks(). Of course, PLL_CON1 registers should be added to corresponding struct samsung_cmu_info::clk_regs array to make sure they get initialized. No functional change. This patch adds a feature, but doesn't enable it for any users. Signed-off-by: Sam Protsenko <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Krzysztof Kozlowski <[email protected]>
1 parent 4cece76 commit 7fa3708

File tree

2 files changed

+45
-15
lines changed

2 files changed

+45
-15
lines changed

drivers/clk/samsung/clk-exynos-arm64.c

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,17 @@
1717

1818
#include "clk-exynos-arm64.h"
1919

20+
/* PLL register bits */
21+
#define PLL_CON1_MANUAL BIT(1)
22+
2023
/* Gate register bits */
2124
#define GATE_MANUAL BIT(20)
2225
#define GATE_ENABLE_HWACG BIT(28)
2326

27+
/* PLL_CONx_PLL register offsets range */
28+
#define PLL_CON_OFF_START 0x100
29+
#define PLL_CON_OFF_END 0x600
30+
2431
/* Gate register offsets range */
2532
#define GATE_OFF_START 0x2000
2633
#define GATE_OFF_END 0x2fff
@@ -38,17 +45,36 @@ struct exynos_arm64_cmu_data {
3845
struct samsung_clk_provider *ctx;
3946
};
4047

48+
/* Check if the register offset is a GATE register */
49+
static bool is_gate_reg(unsigned long off)
50+
{
51+
return off >= GATE_OFF_START && off <= GATE_OFF_END;
52+
}
53+
54+
/* Check if the register offset is a PLL_CONx register */
55+
static bool is_pll_conx_reg(unsigned long off)
56+
{
57+
return off >= PLL_CON_OFF_START && off <= PLL_CON_OFF_END;
58+
}
59+
60+
/* Check if the register offset is a PLL_CON1 register */
61+
static bool is_pll_con1_reg(unsigned long off)
62+
{
63+
return is_pll_conx_reg(off) && (off & 0xf) == 0x4 && !(off & 0x10);
64+
}
65+
4166
/**
4267
* exynos_arm64_init_clocks - Set clocks initial configuration
43-
* @np: CMU device tree node with "reg" property (CMU addr)
44-
* @reg_offs: Register offsets array for clocks to init
45-
* @reg_offs_len: Number of register offsets in reg_offs array
68+
* @np: CMU device tree node with "reg" property (CMU addr)
69+
* @cmu: CMU data
4670
*
47-
* Set manual control mode for all gate clocks.
71+
* Set manual control mode for all gate and PLL clocks.
4872
*/
4973
static void __init exynos_arm64_init_clocks(struct device_node *np,
50-
const unsigned long *reg_offs, size_t reg_offs_len)
74+
const struct samsung_cmu_info *cmu)
5175
{
76+
const unsigned long *reg_offs = cmu->clk_regs;
77+
size_t reg_offs_len = cmu->nr_clk_regs;
5278
void __iomem *reg_base;
5379
size_t i;
5480

@@ -60,14 +86,14 @@ static void __init exynos_arm64_init_clocks(struct device_node *np,
6086
void __iomem *reg = reg_base + reg_offs[i];
6187
u32 val;
6288

63-
/* Modify only gate clock registers */
64-
if (reg_offs[i] < GATE_OFF_START || reg_offs[i] > GATE_OFF_END)
65-
continue;
66-
67-
val = readl(reg);
68-
val |= GATE_MANUAL;
69-
val &= ~GATE_ENABLE_HWACG;
70-
writel(val, reg);
89+
if (cmu->manual_plls && is_pll_con1_reg(reg_offs[i])) {
90+
writel(PLL_CON1_MANUAL, reg);
91+
} else if (is_gate_reg(reg_offs[i])) {
92+
val = readl(reg);
93+
val |= GATE_MANUAL;
94+
val &= ~GATE_ENABLE_HWACG;
95+
writel(val, reg);
96+
}
7197
}
7298

7399
iounmap(reg_base);
@@ -177,7 +203,7 @@ void __init exynos_arm64_register_cmu(struct device *dev,
177203
pr_err("%s: could not enable bus clock %s; err = %d\n",
178204
__func__, cmu->clk_name, err);
179205

180-
exynos_arm64_init_clocks(np, cmu->clk_regs, cmu->nr_clk_regs);
206+
exynos_arm64_init_clocks(np, cmu);
181207
samsung_cmu_register_one(np, cmu);
182208
}
183209

@@ -224,7 +250,7 @@ int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev,
224250
__func__, cmu->clk_name, ret);
225251

226252
if (set_manual)
227-
exynos_arm64_init_clocks(np, cmu->clk_regs, cmu->nr_clk_regs);
253+
exynos_arm64_init_clocks(np, cmu);
228254

229255
reg_base = devm_platform_ioremap_resource(pdev, 0);
230256
if (IS_ERR(reg_base))

drivers/clk/samsung/clk.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ struct samsung_clock_reg_cache {
330330
* @suspend_regs: list of clock registers to set before suspend
331331
* @nr_suspend_regs: count of clock registers in @suspend_regs
332332
* @clk_name: name of the parent clock needed for CMU register access
333+
* @manual_plls: Enable manual control for PLL clocks
333334
*/
334335
struct samsung_cmu_info {
335336
const struct samsung_pll_clock *pll_clks;
@@ -354,6 +355,9 @@ struct samsung_cmu_info {
354355
const struct samsung_clk_reg_dump *suspend_regs;
355356
unsigned int nr_suspend_regs;
356357
const char *clk_name;
358+
359+
/* ARM64 Exynos CMUs */
360+
bool manual_plls;
357361
};
358362

359363
struct samsung_clk_provider *samsung_clk_init(struct device *dev,

0 commit comments

Comments
 (0)