Skip to content

Commit 847eaf0

Browse files
committed
Merge tag 'samsung-clk-6.20' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux into clk-samsung
Pull Samsung clk driver updates from Krzysztof Kozlowski: 1. Add new clock controllers: - MFD for ExynosAutov920 SoC, - Display Process Unit (DPU) for Google GS101 SoC. 2. Implement automatic clock gating mode (HWACG) for Google GS101 SoC clock controllers (but also used on almost all modern Exynos SoC), opposed to currently used mode - manual mode. Background on HW automatic clock gating from Peter Griffin in cover letter: This series addresses an issue with Samsung Exynos based upstream clock driver whereby the upstream clock driver sets all the clock gates into "manual mode" (which uses a bit that is documented as reserved in the gate registers). Another issue with the current "manual clock gating" approach upstream is there are many bus/interconnect clocks whose relationships to the IPs are not well documented or defined in the specs. When adding a new CMU until now we have tried to label these clocks appropriately with CLK_IS_CRITICAL and CLK_IGNORE_UNUSED but doing so is both error prone and time consuming. If your lucky disabling a critical bus clock causes an immediate hang. Other clocks however aren't so obvious and show up through random instability some period of time later. Fortunately each CMU (at least on newer Exynos) provides a "hardware automatic clock gating" HWACG feature that is used by the downstream Samsung clock drivers. Hardware automatic clock gating uses a hardware interface between the CMU and IP to control all clocks required by the IP. This interface is called Q-channel, and is part of the Arm AMBA low power interface specification [1]. The advantage of using this Qchannel hardware interface for enabling/disabling the clocks is that it takes care of all clocks (including bus/interconnect) ones for the IP automatically thereby reducing the dynamic power. Whilst each clock component (GATE, MUX, DIV, QCH etc) has a HWACG enable bit there are also some "global enable override" bits for the entire CMU in the CMU_CONTROLLER_OPTION register. This series makes use of those "global enable" override bits to enable auto clock mode for the entire CMU and every component within it. Through experimentation we can see that setting the "manual mode" reserved gate bit on a particular gate register overides the global enable bits. So the code is updated accordingly not to do that. Auto clock mode has been implemented as a "opt in" by setting a new auto_clock_gate flag in the CMU static data. The intention is existing platforms in manual mode should not be effected by any of these changes. If auto_clock_mode flag is set and the option_offset field is specified then the global enable override bits will be written for the CMU (to avoid relying on any prior bootstage configuration). Again if auto mode is enabled the code no longer sets MANUAL and clears HWACG bits on each gate register. To ensure compatibility with older DTs (that specified an incorrect CMU size) the resource size is checked and the driver falls back to manual clock gate mode in such cases. As the CLK_IGNORE_UNUSED and CLK_IS_CRITICAL flags are required for manual clock gate mode, the patch removing these flags has been dropped from v2. I tested with an old DT and we successfully switch to manual clock gate mode and the system correctly boots. To have dynamic root clock gating (drcg) of bus components and memclk enabled, it is required to set the bus_component_drcg and memclk registers in the correspondingly named sysreg controller. If auto clock mode is enabled the clock driver will now attempt to get the sysreg syscon via the samsung,sysreg property (as used by other Exynos drivers upstream) and set the registers accordingly. The suspend/resume code paths are also updated to handle saving/restoring registers using a regmap. Note cmu_top is an exception and does not have a corresondingly named sysreg_top. As all clock gates are currently exposed in the gs101 drivers and DT, we continue to register all of these gates in auto clock mode, but with some new samsung_auto_clk_gate_ops. As clk enable and clk disable are now handled by Q-channel interface the .enable and .disable implementations are no-ops. However by using some CMU qchannel debug registers we can report the current clock status (enabled or disabled) of every clock gate in the system. This has the nice effect of still being able to dump the entire clock tree from /sys/kernel/debug/clk/clk_summary and see a live view of every auto clock in the system. With the infrastructure in place, all the CMUs registered in clk-gs101 are now updated to enable auto clock mode. From dumping /sys/kernel/debug/clk/clk_summary it is possible to see that after enabling auto clock mode approximately 305 clocks are enabled, and 299 are now disabled. This number goes up and down a bit by 3-5 clocks just on a idle system sat at a console. With auto clock mode enabled it is now also possible to boot without the clk_ignore_unused kernel command line property for the first time! For future CMUs in gs101 I propose we continue to expose all gates, but register the CMU in "auto mode". For new device drivers or updates to existing dt bindings related to clocks to support gs101 I suggest we only use the "obviously correct" clock(s). By "obviously correct" I mean a clock has the IP name in the clock register name, but not try to deduce other obsucurely named bus/interconnect clocks which will now all be handled automatically. Note it is still possible to test whether the "obviously correct" clock is indeed correct by putting the individual gate in manual mode and disabling the clock (e.g. by using devmem). * tag 'samsung-clk-6.20' of https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux: clk: samsung: gs101: add support for Display Process Unit (DPU) clocks dt-bindings: samsung: exynos-sysreg: add gs101 dpu compatible dt-bindings: clock: google,gs101-clock: Add DPU clock management unit dt-bindings: clock: google,gs101-clock: fix alphanumeric ordering clk: samsung: fix sysreg save/restore when PM is enabled for CMU clk: samsung: avoid warning message on legacy Exynos (auto clock gating) clk: samsung: gs101: Enable auto_clock_gate mode for each gs101 CMU clk: samsung: Implement automatic clock gating mode for CMUs dt-bindings: clock: google,gs101-clock: add samsung,sysreg property as required clk: samsung: exynosautov920: add clock support dt-bindings: clock: exynosautov920: add MFD clock definitions
2 parents 8f0b4cc + 4b18a3e commit 847eaf0

16 files changed

Lines changed: 812 additions & 50 deletions

Documentation/devicetree/bindings/clock/google,gs101-clock.yaml

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ properties:
2929
enum:
3030
- google,gs101-cmu-top
3131
- google,gs101-cmu-apm
32-
- google,gs101-cmu-misc
32+
- google,gs101-cmu-dpu
3333
- google,gs101-cmu-hsi0
3434
- google,gs101-cmu-hsi2
35+
- google,gs101-cmu-misc
3536
- google,gs101-cmu-peric0
3637
- google,gs101-cmu-peric1
3738

@@ -52,6 +53,11 @@ properties:
5253
reg:
5354
maxItems: 1
5455

56+
samsung,sysreg:
57+
$ref: /schemas/types.yaml#/definitions/phandle
58+
description:
59+
Phandle to system registers interface.
60+
5561
required:
5662
- compatible
5763
- "#clock-cells"
@@ -77,6 +83,24 @@ allOf:
7783
items:
7884
- const: oscclk
7985

86+
- if:
87+
properties:
88+
compatible:
89+
contains:
90+
const: google,gs101-cmu-dpu
91+
92+
then:
93+
properties:
94+
clocks:
95+
items:
96+
- description: External reference clock (24.576 MHz)
97+
- description: DPU bus clock (from CMU_TOP)
98+
99+
clock-names:
100+
items:
101+
- const: oscclk
102+
- const: bus
103+
80104
- if:
81105
properties:
82106
compatible:
@@ -166,6 +190,18 @@ allOf:
166190
- const: bus
167191
- const: ip
168192

193+
- if:
194+
properties:
195+
compatible:
196+
contains:
197+
const: google,gs101-cmu-top
198+
then:
199+
properties:
200+
samsung,sysreg: false
201+
else:
202+
required:
203+
- samsung,sysreg
204+
169205
additionalProperties: false
170206

171207
examples:
@@ -175,7 +211,7 @@ examples:
175211
176212
cmu_top: clock-controller@1e080000 {
177213
compatible = "google,gs101-cmu-top";
178-
reg = <0x1e080000 0x8000>;
214+
reg = <0x1e080000 0x10000>;
179215
#clock-cells = <1>;
180216
clocks = <&ext_24_5m>;
181217
clock-names = "oscclk";

Documentation/devicetree/bindings/clock/samsung,exynosautov920-clock.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ properties:
4040
- samsung,exynosautov920-cmu-hsi2
4141
- samsung,exynosautov920-cmu-m2m
4242
- samsung,exynosautov920-cmu-mfc
43+
- samsung,exynosautov920-cmu-mfd
4344
- samsung,exynosautov920-cmu-misc
4445
- samsung,exynosautov920-cmu-peric0
4546
- samsung,exynosautov920-cmu-peric1
@@ -268,6 +269,24 @@ allOf:
268269
- const: mfc
269270
- const: wfd
270271

272+
- if:
273+
properties:
274+
compatible:
275+
contains:
276+
const: samsung,exynosautov920-cmu-mfd
277+
278+
then:
279+
properties:
280+
clocks:
281+
items:
282+
- description: External reference clock (38.4 MHz)
283+
- description: CMU_MFD NOC clock (from CMU_TOP)
284+
285+
clock-names:
286+
items:
287+
- const: oscclk
288+
- const: noc
289+
271290
required:
272291
- compatible
273292
- "#clock-cells"

Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ properties:
1515
- items:
1616
- enum:
1717
- google,gs101-apm-sysreg
18+
- google,gs101-dpu-sysreg
1819
- google,gs101-hsi0-sysreg
1920
- google,gs101-hsi2-sysreg
2021
- google,gs101-misc-sysreg
@@ -92,6 +93,7 @@ allOf:
9293
compatible:
9394
contains:
9495
enum:
96+
- google,gs101-dpu-sysreg
9597
- google,gs101-hsi0-sysreg
9698
- google,gs101-hsi2-sysreg
9799
- google,gs101-misc-sysreg

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

Lines changed: 78 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@
2424
#define GATE_MANUAL BIT(20)
2525
#define GATE_ENABLE_HWACG BIT(28)
2626

27+
/* Option register bits */
28+
#define OPT_EN_MEM_PWR_GATING BIT(24)
29+
#define OPT_EN_AUTO_GATING BIT(28)
30+
#define OPT_EN_PWR_MANAGEMENT BIT(29)
31+
#define OPT_EN_LAYER2_CTRL BIT(30)
32+
#define OPT_EN_DBG BIT(31)
33+
34+
#define CMU_OPT_GLOBAL_EN_AUTO_GATING (OPT_EN_DBG | OPT_EN_LAYER2_CTRL | \
35+
OPT_EN_PWR_MANAGEMENT | OPT_EN_AUTO_GATING | OPT_EN_MEM_PWR_GATING)
36+
2737
/* PLL_CONx_PLL register offsets range */
2838
#define PLL_CON_OFF_START 0x100
2939
#define PLL_CON_OFF_END 0x600
@@ -37,6 +47,8 @@ struct exynos_arm64_cmu_data {
3747
unsigned int nr_clk_save;
3848
const struct samsung_clk_reg_dump *clk_suspend;
3949
unsigned int nr_clk_suspend;
50+
struct samsung_clk_reg_dump *clk_sysreg_save;
51+
unsigned int nr_clk_sysreg;
4052

4153
struct clk *clk;
4254
struct clk **pclks;
@@ -76,19 +88,41 @@ static void __init exynos_arm64_init_clocks(struct device_node *np,
7688
const unsigned long *reg_offs = cmu->clk_regs;
7789
size_t reg_offs_len = cmu->nr_clk_regs;
7890
void __iomem *reg_base;
91+
bool init_auto;
7992
size_t i;
8093

8194
reg_base = of_iomap(np, 0);
8295
if (!reg_base)
8396
panic("%s: failed to map registers\n", __func__);
8497

98+
/* ensure compatibility with older DTs */
99+
if (cmu->auto_clock_gate && samsung_is_auto_capable(np))
100+
init_auto = true;
101+
else
102+
init_auto = false;
103+
104+
if (cmu->option_offset && init_auto) {
105+
/*
106+
* Enable the global automatic mode for the entire CMU.
107+
* This overrides the individual HWACG bits in each of the
108+
* individual gate, mux and qch registers.
109+
*/
110+
writel(CMU_OPT_GLOBAL_EN_AUTO_GATING,
111+
reg_base + cmu->option_offset);
112+
}
113+
85114
for (i = 0; i < reg_offs_len; ++i) {
86115
void __iomem *reg = reg_base + reg_offs[i];
87116
u32 val;
88117

89118
if (cmu->manual_plls && is_pll_con1_reg(reg_offs[i])) {
90119
writel(PLL_CON1_MANUAL, reg);
91-
} else if (is_gate_reg(reg_offs[i])) {
120+
} else if (is_gate_reg(reg_offs[i]) && !init_auto) {
121+
/*
122+
* Setting GATE_MANUAL bit (which is described in TRM as
123+
* reserved!) overrides the global CMU automatic mode
124+
* option.
125+
*/
92126
val = readl(reg);
93127
val |= GATE_MANUAL;
94128
val &= ~GATE_ENABLE_HWACG;
@@ -140,40 +174,60 @@ static int __init exynos_arm64_cmu_prepare_pm(struct device *dev,
140174
const struct samsung_cmu_info *cmu)
141175
{
142176
struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev);
143-
int i;
177+
int i, ret;
144178

145179
data->clk_save = samsung_clk_alloc_reg_dump(cmu->clk_regs,
146180
cmu->nr_clk_regs);
147181
if (!data->clk_save)
148182
return -ENOMEM;
149183

150184
data->nr_clk_save = cmu->nr_clk_regs;
185+
186+
if (cmu->nr_sysreg_clk_regs) {
187+
data->clk_sysreg_save =
188+
samsung_clk_alloc_reg_dump(cmu->sysreg_clk_regs,
189+
cmu->nr_sysreg_clk_regs);
190+
if (!data->clk_sysreg_save) {
191+
ret = -ENOMEM;
192+
goto free_clk_save;
193+
}
194+
195+
data->nr_clk_sysreg = cmu->nr_sysreg_clk_regs;
196+
}
197+
151198
data->clk_suspend = cmu->suspend_regs;
152199
data->nr_clk_suspend = cmu->nr_suspend_regs;
200+
153201
data->nr_pclks = of_clk_get_parent_count(dev->of_node);
154202
if (!data->nr_pclks)
155203
return 0;
156204

157205
data->pclks = devm_kcalloc(dev, sizeof(struct clk *), data->nr_pclks,
158206
GFP_KERNEL);
159207
if (!data->pclks) {
160-
kfree(data->clk_save);
161-
return -ENOMEM;
208+
ret = -ENOMEM;
209+
goto free_sysreg_save;
162210
}
163211

164212
for (i = 0; i < data->nr_pclks; i++) {
165213
struct clk *clk = of_clk_get(dev->of_node, i);
166214

167215
if (IS_ERR(clk)) {
168-
kfree(data->clk_save);
169216
while (--i >= 0)
170217
clk_put(data->pclks[i]);
171-
return PTR_ERR(clk);
218+
ret = PTR_ERR(clk);
219+
goto free_sysreg_save;
172220
}
173221
data->pclks[i] = clk;
174222
}
175223

176224
return 0;
225+
226+
free_sysreg_save:
227+
kfree(data->clk_sysreg_save);
228+
free_clk_save:
229+
kfree(data->clk_save);
230+
return ret;
177231
}
178232

179233
/**
@@ -210,16 +264,16 @@ void __init exynos_arm64_register_cmu(struct device *dev,
210264
/**
211265
* exynos_arm64_register_cmu_pm - Register Exynos CMU domain with PM support
212266
*
213-
* @pdev: Platform device object
214-
* @set_manual: If true, set gate clocks to manual mode
267+
* @pdev: Platform device object
268+
* @init_clk_regs: If true, initialize CMU registers
215269
*
216270
* It's a version of exynos_arm64_register_cmu() with PM support. Should be
217271
* called from probe function of platform driver.
218272
*
219273
* Return: 0 on success, or negative error code on error.
220274
*/
221275
int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev,
222-
bool set_manual)
276+
bool init_clk_regs)
223277
{
224278
const struct samsung_cmu_info *cmu;
225279
struct device *dev = &pdev->dev;
@@ -249,7 +303,7 @@ int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev,
249303
dev_err(dev, "%s: could not enable bus clock %s; err = %d\n",
250304
__func__, cmu->clk_name, ret);
251305

252-
if (set_manual)
306+
if (init_clk_regs)
253307
exynos_arm64_init_clocks(np, cmu);
254308

255309
reg_base = devm_platform_ioremap_resource(pdev, 0);
@@ -268,8 +322,10 @@ int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev,
268322
pm_runtime_set_active(dev);
269323
pm_runtime_enable(dev);
270324

271-
samsung_cmu_register_clocks(data->ctx, cmu);
325+
samsung_cmu_register_clocks(data->ctx, cmu, np);
272326
samsung_clk_of_add_provider(dev->of_node, data->ctx);
327+
/* sysreg DT nodes reference a clock in this CMU */
328+
samsung_en_dyn_root_clk_gating(np, data->ctx, cmu, true);
273329
pm_runtime_put_sync(dev);
274330

275331
return 0;
@@ -280,14 +336,17 @@ int exynos_arm64_cmu_suspend(struct device *dev)
280336
struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev);
281337
int i;
282338

283-
samsung_clk_save(data->ctx->reg_base, data->clk_save,
339+
samsung_clk_save(data->ctx->reg_base, NULL, data->clk_save,
284340
data->nr_clk_save);
285341

342+
samsung_clk_save(NULL, data->ctx->sysreg, data->clk_sysreg_save,
343+
data->nr_clk_sysreg);
344+
286345
for (i = 0; i < data->nr_pclks; i++)
287346
clk_prepare_enable(data->pclks[i]);
288347

289348
/* For suspend some registers have to be set to certain values */
290-
samsung_clk_restore(data->ctx->reg_base, data->clk_suspend,
349+
samsung_clk_restore(data->ctx->reg_base, NULL, data->clk_suspend,
291350
data->nr_clk_suspend);
292351

293352
for (i = 0; i < data->nr_pclks; i++)
@@ -308,9 +367,14 @@ int exynos_arm64_cmu_resume(struct device *dev)
308367
for (i = 0; i < data->nr_pclks; i++)
309368
clk_prepare_enable(data->pclks[i]);
310369

311-
samsung_clk_restore(data->ctx->reg_base, data->clk_save,
370+
samsung_clk_restore(data->ctx->reg_base, NULL, data->clk_save,
312371
data->nr_clk_save);
313372

373+
if (data->ctx->sysreg)
374+
samsung_clk_restore(NULL, data->ctx->sysreg,
375+
data->clk_sysreg_save,
376+
data->nr_clk_sysreg);
377+
314378
for (i = 0; i < data->nr_pclks; i++)
315379
clk_disable_unprepare(data->pclks[i]);
316380

drivers/clk/samsung/clk-exynos4.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,12 +1361,12 @@ static void __init exynos4_clk_init(struct device_node *np,
13611361
ARRAY_SIZE(exynos4x12_plls));
13621362
}
13631363

1364-
samsung_cmu_register_clocks(ctx, &cmu_info_exynos4);
1364+
samsung_cmu_register_clocks(ctx, &cmu_info_exynos4, np);
13651365

13661366
if (exynos4_soc == EXYNOS4210) {
1367-
samsung_cmu_register_clocks(ctx, &cmu_info_exynos4210);
1367+
samsung_cmu_register_clocks(ctx, &cmu_info_exynos4210, np);
13681368
} else {
1369-
samsung_cmu_register_clocks(ctx, &cmu_info_exynos4x12);
1369+
samsung_cmu_register_clocks(ctx, &cmu_info_exynos4x12, np);
13701370
if (soc == EXYNOS4412)
13711371
samsung_clk_register_cpu(ctx, exynos4412_cpu_clks,
13721372
ARRAY_SIZE(exynos4412_cpu_clks));
@@ -1378,15 +1378,15 @@ static void __init exynos4_clk_init(struct device_node *np,
13781378
if (soc == EXYNOS4212 || soc == EXYNOS4412)
13791379
exynos4x12_core_down_clock();
13801380

1381-
samsung_clk_extended_sleep_init(reg_base,
1381+
samsung_clk_extended_sleep_init(reg_base, NULL,
13821382
exynos4_clk_regs, ARRAY_SIZE(exynos4_clk_regs),
13831383
src_mask_suspend, ARRAY_SIZE(src_mask_suspend));
13841384
if (exynos4_soc == EXYNOS4210)
1385-
samsung_clk_extended_sleep_init(reg_base,
1385+
samsung_clk_extended_sleep_init(reg_base, NULL,
13861386
exynos4210_clk_save, ARRAY_SIZE(exynos4210_clk_save),
13871387
src_mask_suspend_e4210, ARRAY_SIZE(src_mask_suspend_e4210));
13881388
else
1389-
samsung_clk_sleep_init(reg_base, exynos4x12_clk_save,
1389+
samsung_clk_sleep_init(reg_base, NULL, exynos4x12_clk_save,
13901390
ARRAY_SIZE(exynos4x12_clk_save));
13911391

13921392
samsung_clk_of_add_provider(np, ctx);

drivers/clk/samsung/clk-exynos4412-isp.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ static int __maybe_unused exynos4x12_isp_clk_suspend(struct device *dev)
9494
{
9595
struct samsung_clk_provider *ctx = dev_get_drvdata(dev);
9696

97-
samsung_clk_save(ctx->reg_base, exynos4x12_save_isp,
97+
samsung_clk_save(ctx->reg_base, NULL, exynos4x12_save_isp,
9898
ARRAY_SIZE(exynos4x12_clk_isp_save));
9999
return 0;
100100
}
@@ -103,7 +103,7 @@ static int __maybe_unused exynos4x12_isp_clk_resume(struct device *dev)
103103
{
104104
struct samsung_clk_provider *ctx = dev_get_drvdata(dev);
105105

106-
samsung_clk_restore(ctx->reg_base, exynos4x12_save_isp,
106+
samsung_clk_restore(ctx->reg_base, NULL, exynos4x12_save_isp,
107107
ARRAY_SIZE(exynos4x12_clk_isp_save));
108108
return 0;
109109
}

drivers/clk/samsung/clk-exynos5250.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -854,7 +854,7 @@ static void __init exynos5250_clk_init(struct device_node *np)
854854
PWR_CTRL2_CORE2_UP_RATIO | PWR_CTRL2_CORE1_UP_RATIO);
855855
__raw_writel(tmp, reg_base + PWR_CTRL2);
856856

857-
samsung_clk_sleep_init(reg_base, exynos5250_clk_regs,
857+
samsung_clk_sleep_init(reg_base, NULL, exynos5250_clk_regs,
858858
ARRAY_SIZE(exynos5250_clk_regs));
859859
exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5250_subcmus),
860860
exynos5250_subcmus);

0 commit comments

Comments
 (0)