* [PATCH v4 0/4] Implement hardware automatic clock gating (HWACG) for gs101
@ 2025-11-10 14:21 Peter Griffin
2025-11-10 14:21 ` [PATCH v4 1/4] dt-bindings: clock: google,gs101-clock: add samsung,sysreg property as required Peter Griffin
` (3 more replies)
0 siblings, 4 replies; 8+ messages in thread
From: Peter Griffin @ 2025-11-10 14:21 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Alim Akhtar,
André Draszik, Tudor Ambarus, Michael Turquette,
Stephen Boyd, Sam Protsenko, Sylwester Nawrocki, Chanwoo Choi
Cc: Will McVicker, Krzysztof Kozlowski, devicetree, linux-arm-kernel,
linux-samsung-soc, linux-kernel, linux-clk, kernel-team,
Peter Griffin, Krzysztof Kozlowski
Hi folks,
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).
Note: As everything here will go via one of Krzysztof's trees I've sent it
as one series.
regards,
Peter
[1] https://documentation-service.arm.com/static/5f915e69f86e16515cdc3b3e?token=
Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
---
Changes in v4:
- Update commit description with additional requested details (Krzysztof)
- Remove unnecessary header of_address.h (Peter)
- Link to v3: https://lore.kernel.org/r/20251102-automatic-clocks-v3-0-ff10eafe61c8@linaro.org
Changes in v3:
- Add missing 'np' func param to kerneldoc in samsung_cmu_register_clocks
(0-DAY CI )
- Link to v2: https://lore.kernel.org/r/20251029-automatic-clocks-v2-0-f8edd3a2d82b@linaro.org
Changes in v2:
- Rebased onto next-20251024
- Fallback to manual clock gate mode for old DTs with incorrect CMU reg
size (added samsung_is_auto_capable(). Tested with old DT and it works as
expected. It does require keeping all the CLK_IS_CRITICAL
CLK_IGNORE_UNUSED flags in clk-gs101 so patch removing those is
dropped. (Krzysztof)
- Rename OPT_UNKNOWN bit to OPT_EN_LAYER2_CTRL (Andre)
- Rename OPT_EN_MEM_PM_GATING to OPT_EN_MEM_PWR_GATING (Peter)
- Reverse Option bit definitions LSB -> MSB (Krzysztof)
- Update kerneldoc init_clk_regs comment (Andre)
- Fix space on various comments (Andre)
- Fix regmap typo on samsung_clk_save/restore calls (Andre)
- Include error code in pr_err message (Andre)
- Add macros for dcrg and memclk (Andre)
- Avoid confusing !IS_ERR_OR_NULL(ctx->sysreg) test (Krzysztof)
- Update kerneldoc to mention drcg_offset & memclk_offset are in sysreg
(Andre)
- Update bindings commit description as to why the sysreg is required
(Krzysztof)
- Link to v1: https://lore.kernel.org/r/20251013-automatic-clocks-v1-0-72851ee00300@linaro.org
---
Peter Griffin (4):
dt-bindings: clock: google,gs101-clock: add samsung,sysreg property as required
arm64: dts: exynos: gs101: add samsung,sysreg property to CMU nodes
clk: samsung: Implement automatic clock gating mode for CMUs
clk: samsung: gs101: Enable auto_clock_gate mode for each gs101 CMU
.../bindings/clock/google,gs101-clock.yaml | 23 ++-
arch/arm64/boot/dts/exynos/google/gs101.dtsi | 6 +
drivers/clk/samsung/clk-exynos-arm64.c | 62 ++++++-
drivers/clk/samsung/clk-exynos4.c | 12 +-
drivers/clk/samsung/clk-exynos4412-isp.c | 4 +-
drivers/clk/samsung/clk-exynos5250.c | 2 +-
drivers/clk/samsung/clk-exynos5420.c | 4 +-
drivers/clk/samsung/clk-gs101.c | 55 ++++++
drivers/clk/samsung/clk-s3c64xx.c | 4 +-
drivers/clk/samsung/clk-s5pv210.c | 2 +-
drivers/clk/samsung/clk.c | 200 +++++++++++++++++++--
drivers/clk/samsung/clk.h | 55 +++++-
12 files changed, 385 insertions(+), 44 deletions(-)
---
base-commit: 72fb0170ef1f45addf726319c52a0562b6913707
change-id: 20251008-automatic-clocks-249ab60f62ce
Best regards,
--
Peter Griffin <peter.griffin@linaro.org>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v4 1/4] dt-bindings: clock: google,gs101-clock: add samsung,sysreg property as required
2025-11-10 14:21 [PATCH v4 0/4] Implement hardware automatic clock gating (HWACG) for gs101 Peter Griffin
@ 2025-11-10 14:21 ` Peter Griffin
2025-11-11 9:54 ` André Draszik
2025-11-10 14:21 ` [PATCH v4 2/4] arm64: dts: exynos: gs101: add samsung,sysreg property to CMU nodes Peter Griffin
` (2 subsequent siblings)
3 siblings, 1 reply; 8+ messages in thread
From: Peter Griffin @ 2025-11-10 14:21 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Alim Akhtar,
André Draszik, Tudor Ambarus, Michael Turquette,
Stephen Boyd, Sam Protsenko, Sylwester Nawrocki, Chanwoo Choi
Cc: Will McVicker, Krzysztof Kozlowski, devicetree, linux-arm-kernel,
linux-samsung-soc, linux-kernel, linux-clk, kernel-team,
Peter Griffin, Krzysztof Kozlowski
Each CMU (with the exception of cmu_top) has a corresponding sysreg bank
that contains the BUSCOMPONENT_DRCG_EN and optional MEMCLK registers.
The BUSCOMPONENT_DRCG_EN register enables dynamic root clock gating of
bus components and MEMCLK gates the sram clock.
Now the clock driver supports automatic clock mode, to fully enable dynamic
root clock gating it is required to configure these registers. Update the
bindings documentation so that all CMUs (with the exception of
gs101-cmu-top) have samsung,sysreg as a required property.
Note this is NOT an ABI break, as if the property isn't specified the
clock driver will fallback to the current behaviour of not initializing
the registers. The system still boots, but bus components won't benefit
from dynamic root clock gating and dynamic power will be higher (which has
been the case until now anyway).
Additionally update the DT example to included the correct CMU size as
registers in that region are used for automatic clock mode.
Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
---
Changes in v4
- Update commit description with additional requested details (Krzysztof)
Changes in v3:
- Update commit description as to why the sysreg is required (Krzysztof)
Changes in v2:
- Update commit description regarding updated example (Andre)
---
.../bindings/clock/google,gs101-clock.yaml | 23 +++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml b/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
index 31e106ef913dead9a038b3b6d8b43b950587f6aa..5ce5ba523110af3a2a7740b8ba28e2271c76bddb 100644
--- a/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
@@ -52,6 +52,11 @@ properties:
reg:
maxItems: 1
+ samsung,sysreg:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ Phandle to system registers interface.
+
required:
- compatible
- "#clock-cells"
@@ -166,6 +171,22 @@ allOf:
- const: bus
- const: ip
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - google,gs101-cmu-apm
+ - google,gs101-cmu-misc
+ - google,gs101-hsi0
+ - google,gs101-cmu-hsi2
+ - google,gs101-cmu-peric0
+ - google,gs101-cmu-peric1
+
+ then:
+ required:
+ - samsung,sysreg
+
additionalProperties: false
examples:
@@ -175,7 +196,7 @@ examples:
cmu_top: clock-controller@1e080000 {
compatible = "google,gs101-cmu-top";
- reg = <0x1e080000 0x8000>;
+ reg = <0x1e080000 0x10000>;
#clock-cells = <1>;
clocks = <&ext_24_5m>;
clock-names = "oscclk";
--
2.51.2.1041.gc1ab5b90ca-goog
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v4 2/4] arm64: dts: exynos: gs101: add samsung,sysreg property to CMU nodes
2025-11-10 14:21 [PATCH v4 0/4] Implement hardware automatic clock gating (HWACG) for gs101 Peter Griffin
2025-11-10 14:21 ` [PATCH v4 1/4] dt-bindings: clock: google,gs101-clock: add samsung,sysreg property as required Peter Griffin
@ 2025-11-10 14:21 ` Peter Griffin
2025-11-10 14:21 ` [PATCH v4 3/4] clk: samsung: Implement automatic clock gating mode for CMUs Peter Griffin
2025-11-10 14:21 ` [PATCH v4 4/4] clk: samsung: gs101: Enable auto_clock_gate mode for each gs101 CMU Peter Griffin
3 siblings, 0 replies; 8+ messages in thread
From: Peter Griffin @ 2025-11-10 14:21 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Alim Akhtar,
André Draszik, Tudor Ambarus, Michael Turquette,
Stephen Boyd, Sam Protsenko, Sylwester Nawrocki, Chanwoo Choi
Cc: Will McVicker, Krzysztof Kozlowski, devicetree, linux-arm-kernel,
linux-samsung-soc, linux-kernel, linux-clk, kernel-team,
Peter Griffin, Krzysztof Kozlowski
With the exception of cmu_top, each CMU has a corresponding sysreg bank
that contains the BUSCOMPONENT_DRCG_EN and optional MEMCLK registers.
The BUSCOMPONENT_DRCG_EN register enables dynamic root clock gating of
bus components and MEMCLK gates the sram clock.
Now the clock driver supports automatic clock mode, provide the
samsung,sysreg property so the driver can enable dynamic root clock
gating of bus components and gate sram clock.
Note without the property specified the driver simply falls back to
previous behaviour of not configuring these registers so it is not an ABI
break.
Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
---
Changes in v4:
- Update commit message (Peter)
---
arch/arm64/boot/dts/exynos/google/gs101.dtsi | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm64/boot/dts/exynos/google/gs101.dtsi b/arch/arm64/boot/dts/exynos/google/gs101.dtsi
index d06d1d05f36408137a8acd98e43d48ea7d4f4292..c39ca4c4508f046ca16ae86be42468c7245561b8 100644
--- a/arch/arm64/boot/dts/exynos/google/gs101.dtsi
+++ b/arch/arm64/boot/dts/exynos/google/gs101.dtsi
@@ -578,6 +578,7 @@ cmu_misc: clock-controller@10010000 {
clocks = <&cmu_top CLK_DOUT_CMU_MISC_BUS>,
<&cmu_top CLK_DOUT_CMU_MISC_SSS>;
clock-names = "bus", "sss";
+ samsung,sysreg = <&sysreg_misc>;
};
sysreg_misc: syscon@10030000 {
@@ -662,6 +663,7 @@ cmu_peric0: clock-controller@10800000 {
<&cmu_top CLK_DOUT_CMU_PERIC0_BUS>,
<&cmu_top CLK_DOUT_CMU_PERIC0_IP>;
clock-names = "oscclk", "bus", "ip";
+ samsung,sysreg = <&sysreg_peric0>;
};
sysreg_peric0: syscon@10820000 {
@@ -1208,6 +1210,7 @@ cmu_peric1: clock-controller@10c00000 {
<&cmu_top CLK_DOUT_CMU_PERIC1_BUS>,
<&cmu_top CLK_DOUT_CMU_PERIC1_IP>;
clock-names = "oscclk", "bus", "ip";
+ samsung,sysreg = <&sysreg_peric1>;
};
sysreg_peric1: syscon@10c20000 {
@@ -1566,6 +1569,7 @@ cmu_hsi0: clock-controller@11000000 {
<&cmu_top CLK_DOUT_CMU_HSI0_USBDPDBG>;
clock-names = "oscclk", "bus", "dpgtc", "usb31drd",
"usbdpdbg";
+ samsung,sysreg = <&sysreg_hsi0>;
};
sysreg_hsi0: syscon@11020000 {
@@ -1637,6 +1641,7 @@ cmu_hsi2: clock-controller@14400000 {
<&cmu_top CLK_DOUT_CMU_HSI2_UFS_EMBD>,
<&cmu_top CLK_DOUT_CMU_HSI2_MMC_CARD>;
clock-names = "oscclk", "bus", "pcie", "ufs", "mmc";
+ samsung,sysreg = <&sysreg_hsi2>;
};
sysreg_hsi2: syscon@14420000 {
@@ -1697,6 +1702,7 @@ cmu_apm: clock-controller@17400000 {
clocks = <&ext_24_5m>;
clock-names = "oscclk";
+ samsung,sysreg = <&sysreg_apm>;
};
sysreg_apm: syscon@17420000 {
--
2.51.2.1041.gc1ab5b90ca-goog
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v4 3/4] clk: samsung: Implement automatic clock gating mode for CMUs
2025-11-10 14:21 [PATCH v4 0/4] Implement hardware automatic clock gating (HWACG) for gs101 Peter Griffin
2025-11-10 14:21 ` [PATCH v4 1/4] dt-bindings: clock: google,gs101-clock: add samsung,sysreg property as required Peter Griffin
2025-11-10 14:21 ` [PATCH v4 2/4] arm64: dts: exynos: gs101: add samsung,sysreg property to CMU nodes Peter Griffin
@ 2025-11-10 14:21 ` Peter Griffin
2025-11-10 14:21 ` [PATCH v4 4/4] clk: samsung: gs101: Enable auto_clock_gate mode for each gs101 CMU Peter Griffin
3 siblings, 0 replies; 8+ messages in thread
From: Peter Griffin @ 2025-11-10 14:21 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Alim Akhtar,
André Draszik, Tudor Ambarus, Michael Turquette,
Stephen Boyd, Sam Protsenko, Sylwester Nawrocki, Chanwoo Choi
Cc: Will McVicker, Krzysztof Kozlowski, devicetree, linux-arm-kernel,
linux-samsung-soc, linux-kernel, linux-clk, kernel-team,
Peter Griffin, Krzysztof Kozlowski
Update exynos_arm64_init_clocks() so that it enables the automatic clock
mode bits in the CMU option register if the auto_clock_gate flag and
option_offset fields are set for the CMU. To ensure compatibility with
older DTs (that specified an incorrect CMU reg size), detect this and
fallback to manual clock gate mode as the auto clock mode feature depends
on registers in this area.
The CMU option register bits are global and effect every clock component in
the CMU, as such clearing the GATE_ENABLE_HWACG bit and setting GATE_MANUAL
bit on every gate register is only required if auto_clock_gate is false.
Additionally if auto_clock_gate is enabled the dynamic root clock gating
and memclk registers will be configured in the corresponding CMUs sysreg
bank. These registers are exposed via syscon, so the register
samsung_clk_save/restore paths are updated to also take a regmap.
As many gates for various Samsung SoCs are already exposed in the Samsung
clock drivers a new samsung_auto_clk_gate_ops is implemented. This uses
some CMU debug registers to report whether clocks are enabled or disabled
when operating in automatic mode. This allows
/sys/kernel/debug/clk/clk_summary to still dump the entire clock tree and
correctly report the status of each clock in the system.
Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
---
Changes in v3:
- Add missing 'np' func param to kerneldoc in samsung_cmu_register_clocks
(0-DAY CI)
Changes in v2:
- Fallback to manual clock gate mode for old DTs with incorrect CMU size
(added samsung_is_auto_capable()) (Krzysztof)
- Rename OPT_UNKNOWN bit to OPT_EN_LAYER2_CTRL (Andre)
- Rename OPT_EN_MEM_PM_GATING to OPT_EN_MEM_PWR_GATING (Andre)
- Reverse Option bit definitions LSB -> MSB (Krzysztof)
- Update kerneldoc init_clk_regs comment (Andre)
- Fix space on various comments (Andre)
- Fix regmap typo on samsung_clk_save/restore calls (Andre)
- Include error code in pr_err message (Andre)
- Add macros for dcrg and memclk (Andre)
- Avoid confusing !IS_ERR_OR_NULL(ctx->sysreg) test (Krzysztof)
- Update kerneldoc to mention drcg_offset & memclk_offset are in sysreg (Andre)
- Fix 0-DAY CI randconfig warning (0-DAY CI)
- Update clk-s5pv210 and clk-s3c64xx.c samsung_clk_sleep_init call sites (Peter)
---
drivers/clk/samsung/clk-exynos-arm64.c | 62 ++++++++--
drivers/clk/samsung/clk-exynos4.c | 12 +-
drivers/clk/samsung/clk-exynos4412-isp.c | 4 +-
drivers/clk/samsung/clk-exynos5250.c | 2 +-
drivers/clk/samsung/clk-exynos5420.c | 4 +-
drivers/clk/samsung/clk-s3c64xx.c | 4 +-
drivers/clk/samsung/clk-s5pv210.c | 2 +-
drivers/clk/samsung/clk.c | 200 ++++++++++++++++++++++++++++---
drivers/clk/samsung/clk.h | 55 ++++++++-
9 files changed, 302 insertions(+), 43 deletions(-)
diff --git a/drivers/clk/samsung/clk-exynos-arm64.c b/drivers/clk/samsung/clk-exynos-arm64.c
index bf7de21f329ec89069dcf817ca578fcf9b2d9809..11e4d49f2390ba714eff5a329bb1f427cd6437b9 100644
--- a/drivers/clk/samsung/clk-exynos-arm64.c
+++ b/drivers/clk/samsung/clk-exynos-arm64.c
@@ -24,6 +24,16 @@
#define GATE_MANUAL BIT(20)
#define GATE_ENABLE_HWACG BIT(28)
+/* Option register bits */
+#define OPT_EN_MEM_PWR_GATING BIT(24)
+#define OPT_EN_AUTO_GATING BIT(28)
+#define OPT_EN_PWR_MANAGEMENT BIT(29)
+#define OPT_EN_LAYER2_CTRL BIT(30)
+#define OPT_EN_DBG BIT(31)
+
+#define CMU_OPT_GLOBAL_EN_AUTO_GATING (OPT_EN_DBG | OPT_EN_LAYER2_CTRL | \
+ OPT_EN_PWR_MANAGEMENT | OPT_EN_AUTO_GATING | OPT_EN_MEM_PWR_GATING)
+
/* PLL_CONx_PLL register offsets range */
#define PLL_CON_OFF_START 0x100
#define PLL_CON_OFF_END 0x600
@@ -37,6 +47,8 @@ struct exynos_arm64_cmu_data {
unsigned int nr_clk_save;
const struct samsung_clk_reg_dump *clk_suspend;
unsigned int nr_clk_suspend;
+ struct samsung_clk_reg_dump *clk_sysreg_save;
+ unsigned int nr_clk_sysreg;
struct clk *clk;
struct clk **pclks;
@@ -76,19 +88,41 @@ static void __init exynos_arm64_init_clocks(struct device_node *np,
const unsigned long *reg_offs = cmu->clk_regs;
size_t reg_offs_len = cmu->nr_clk_regs;
void __iomem *reg_base;
+ bool init_auto;
size_t i;
reg_base = of_iomap(np, 0);
if (!reg_base)
panic("%s: failed to map registers\n", __func__);
+ /* ensure compatibility with older DTs */
+ if (cmu->auto_clock_gate && samsung_is_auto_capable(np))
+ init_auto = true;
+ else
+ init_auto = false;
+
+ if (cmu->option_offset && init_auto) {
+ /*
+ * Enable the global automatic mode for the entire CMU.
+ * This overrides the individual HWACG bits in each of the
+ * individual gate, mux and qch registers.
+ */
+ writel(CMU_OPT_GLOBAL_EN_AUTO_GATING,
+ reg_base + cmu->option_offset);
+ }
+
for (i = 0; i < reg_offs_len; ++i) {
void __iomem *reg = reg_base + reg_offs[i];
u32 val;
if (cmu->manual_plls && is_pll_con1_reg(reg_offs[i])) {
writel(PLL_CON1_MANUAL, reg);
- } else if (is_gate_reg(reg_offs[i])) {
+ } else if (is_gate_reg(reg_offs[i]) && !init_auto) {
+ /*
+ * Setting GATE_MANUAL bit (which is described in TRM as
+ * reserved!) overrides the global CMU automatic mode
+ * option.
+ */
val = readl(reg);
val |= GATE_MANUAL;
val &= ~GATE_ENABLE_HWACG;
@@ -210,8 +244,8 @@ void __init exynos_arm64_register_cmu(struct device *dev,
/**
* 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
+ * @pdev: Platform device object
+ * @init_clk_regs: If true, initialize CMU registers
*
* It's a version of exynos_arm64_register_cmu() with PM support. Should be
* called from probe function of platform driver.
@@ -219,7 +253,7 @@ void __init exynos_arm64_register_cmu(struct device *dev,
* Return: 0 on success, or negative error code on error.
*/
int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev,
- bool set_manual)
+ bool init_clk_regs)
{
const struct samsung_cmu_info *cmu;
struct device *dev = &pdev->dev;
@@ -249,7 +283,7 @@ int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev,
dev_err(dev, "%s: could not enable bus clock %s; err = %d\n",
__func__, cmu->clk_name, ret);
- if (set_manual)
+ if (init_clk_regs)
exynos_arm64_init_clocks(np, cmu);
reg_base = devm_platform_ioremap_resource(pdev, 0);
@@ -268,8 +302,10 @@ int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev,
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
- samsung_cmu_register_clocks(data->ctx, cmu);
+ samsung_cmu_register_clocks(data->ctx, cmu, np);
samsung_clk_of_add_provider(dev->of_node, data->ctx);
+ /* sysreg DT nodes reference a clock in this CMU */
+ samsung_en_dyn_root_clk_gating(np, data->ctx, cmu);
pm_runtime_put_sync(dev);
return 0;
@@ -280,14 +316,17 @@ 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,
+ samsung_clk_save(data->ctx->reg_base, NULL, data->clk_save,
data->nr_clk_save);
+ samsung_clk_save(NULL, data->ctx->sysreg, data->clk_sysreg_save,
+ data->nr_clk_sysreg);
+
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,
+ samsung_clk_restore(data->ctx->reg_base, NULL, data->clk_suspend,
data->nr_clk_suspend);
for (i = 0; i < data->nr_pclks; i++)
@@ -308,9 +347,14 @@ int exynos_arm64_cmu_resume(struct device *dev)
for (i = 0; i < data->nr_pclks; i++)
clk_prepare_enable(data->pclks[i]);
- samsung_clk_restore(data->ctx->reg_base, data->clk_save,
+ samsung_clk_restore(data->ctx->reg_base, NULL, data->clk_save,
data->nr_clk_save);
+ if (data->ctx->sysreg)
+ samsung_clk_restore(NULL, data->ctx->sysreg,
+ data->clk_sysreg_save,
+ data->nr_clk_sysreg);
+
for (i = 0; i < data->nr_pclks; i++)
clk_disable_unprepare(data->pclks[i]);
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index cc5c1644c41c08b27bc48d809a08cd8a006cbe8f..246bd28bac2d577a58a7b9e0e93b700548370a36 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -1361,12 +1361,12 @@ static void __init exynos4_clk_init(struct device_node *np,
ARRAY_SIZE(exynos4x12_plls));
}
- samsung_cmu_register_clocks(ctx, &cmu_info_exynos4);
+ samsung_cmu_register_clocks(ctx, &cmu_info_exynos4, np);
if (exynos4_soc == EXYNOS4210) {
- samsung_cmu_register_clocks(ctx, &cmu_info_exynos4210);
+ samsung_cmu_register_clocks(ctx, &cmu_info_exynos4210, np);
} else {
- samsung_cmu_register_clocks(ctx, &cmu_info_exynos4x12);
+ samsung_cmu_register_clocks(ctx, &cmu_info_exynos4x12, np);
if (soc == EXYNOS4412)
samsung_clk_register_cpu(ctx, exynos4412_cpu_clks,
ARRAY_SIZE(exynos4412_cpu_clks));
@@ -1378,15 +1378,15 @@ static void __init exynos4_clk_init(struct device_node *np,
if (soc == EXYNOS4212 || soc == EXYNOS4412)
exynos4x12_core_down_clock();
- samsung_clk_extended_sleep_init(reg_base,
+ samsung_clk_extended_sleep_init(reg_base, NULL,
exynos4_clk_regs, ARRAY_SIZE(exynos4_clk_regs),
src_mask_suspend, ARRAY_SIZE(src_mask_suspend));
if (exynos4_soc == EXYNOS4210)
- samsung_clk_extended_sleep_init(reg_base,
+ samsung_clk_extended_sleep_init(reg_base, NULL,
exynos4210_clk_save, ARRAY_SIZE(exynos4210_clk_save),
src_mask_suspend_e4210, ARRAY_SIZE(src_mask_suspend_e4210));
else
- samsung_clk_sleep_init(reg_base, exynos4x12_clk_save,
+ samsung_clk_sleep_init(reg_base, NULL, exynos4x12_clk_save,
ARRAY_SIZE(exynos4x12_clk_save));
samsung_clk_of_add_provider(np, ctx);
diff --git a/drivers/clk/samsung/clk-exynos4412-isp.c b/drivers/clk/samsung/clk-exynos4412-isp.c
index fa915057e109e0008ebe0b1b5d1652fd5804e82b..772bc18a1e686f23b11bf160b803becff6279637 100644
--- a/drivers/clk/samsung/clk-exynos4412-isp.c
+++ b/drivers/clk/samsung/clk-exynos4412-isp.c
@@ -94,7 +94,7 @@ static int __maybe_unused exynos4x12_isp_clk_suspend(struct device *dev)
{
struct samsung_clk_provider *ctx = dev_get_drvdata(dev);
- samsung_clk_save(ctx->reg_base, exynos4x12_save_isp,
+ samsung_clk_save(ctx->reg_base, NULL, exynos4x12_save_isp,
ARRAY_SIZE(exynos4x12_clk_isp_save));
return 0;
}
@@ -103,7 +103,7 @@ static int __maybe_unused exynos4x12_isp_clk_resume(struct device *dev)
{
struct samsung_clk_provider *ctx = dev_get_drvdata(dev);
- samsung_clk_restore(ctx->reg_base, exynos4x12_save_isp,
+ samsung_clk_restore(ctx->reg_base, NULL, exynos4x12_save_isp,
ARRAY_SIZE(exynos4x12_clk_isp_save));
return 0;
}
diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c
index e90d3a0848cbc24b2709c10795f6affcda404567..f97f30b29be7317db8186bac39cf52e1893eb106 100644
--- a/drivers/clk/samsung/clk-exynos5250.c
+++ b/drivers/clk/samsung/clk-exynos5250.c
@@ -854,7 +854,7 @@ static void __init exynos5250_clk_init(struct device_node *np)
PWR_CTRL2_CORE2_UP_RATIO | PWR_CTRL2_CORE1_UP_RATIO);
__raw_writel(tmp, reg_base + PWR_CTRL2);
- samsung_clk_sleep_init(reg_base, exynos5250_clk_regs,
+ samsung_clk_sleep_init(reg_base, NULL, exynos5250_clk_regs,
ARRAY_SIZE(exynos5250_clk_regs));
exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5250_subcmus),
exynos5250_subcmus);
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c
index a9df4e6db82fa7831d4e5c7210b0163d7d301ec1..1982e0751ceec7e57f9e82d96dcbadce1f691092 100644
--- a/drivers/clk/samsung/clk-exynos5420.c
+++ b/drivers/clk/samsung/clk-exynos5420.c
@@ -1649,12 +1649,12 @@ static void __init exynos5x_clk_init(struct device_node *np,
ARRAY_SIZE(exynos5800_cpu_clks));
}
- samsung_clk_extended_sleep_init(reg_base,
+ samsung_clk_extended_sleep_init(reg_base, NULL,
exynos5x_clk_regs, ARRAY_SIZE(exynos5x_clk_regs),
exynos5420_set_clksrc, ARRAY_SIZE(exynos5420_set_clksrc));
if (soc == EXYNOS5800) {
- samsung_clk_sleep_init(reg_base, exynos5800_clk_regs,
+ samsung_clk_sleep_init(reg_base, NULL, exynos5800_clk_regs,
ARRAY_SIZE(exynos5800_clk_regs));
exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5800_subcmus),
diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c
index 397a057af5d1e704e7ead7ba04b477fdc28c45bf..5a2d5a5703ffc5ed48b9a18a20c39be2de827920 100644
--- a/drivers/clk/samsung/clk-s3c64xx.c
+++ b/drivers/clk/samsung/clk-s3c64xx.c
@@ -449,10 +449,10 @@ void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f,
samsung_clk_register_alias(ctx, s3c64xx_clock_aliases,
ARRAY_SIZE(s3c64xx_clock_aliases));
- samsung_clk_sleep_init(reg_base, s3c64xx_clk_regs,
+ samsung_clk_sleep_init(reg_base, NULL, s3c64xx_clk_regs,
ARRAY_SIZE(s3c64xx_clk_regs));
if (!is_s3c6400)
- samsung_clk_sleep_init(reg_base, s3c6410_clk_regs,
+ samsung_clk_sleep_init(reg_base, NULL, s3c6410_clk_regs,
ARRAY_SIZE(s3c6410_clk_regs));
samsung_clk_of_add_provider(np, ctx);
diff --git a/drivers/clk/samsung/clk-s5pv210.c b/drivers/clk/samsung/clk-s5pv210.c
index 9a4217cc1908aa60ebbe51b2b5c841138cc46ef3..4ee4f2b5efbc1d4770fefff22de21f7d4e5e9506 100644
--- a/drivers/clk/samsung/clk-s5pv210.c
+++ b/drivers/clk/samsung/clk-s5pv210.c
@@ -782,7 +782,7 @@ static void __init __s5pv210_clk_init(struct device_node *np,
samsung_clk_register_alias(ctx, s5pv210_aliases,
ARRAY_SIZE(s5pv210_aliases));
- samsung_clk_sleep_init(reg_base, s5pv210_clk_regs,
+ samsung_clk_sleep_init(reg_base, NULL, s5pv210_clk_regs,
ARRAY_SIZE(s5pv210_clk_regs));
samsung_clk_of_add_provider(np, ctx);
diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
index dbc9925ca8f46e951dfb5d391c0e744ca370abcc..83de526346bc06c811beac3667bab482e2eca7b8 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -12,8 +12,10 @@
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
+#include <linux/mfd/syscon.h>
#include <linux/mod_devicetable.h>
#include <linux/of_address.h>
+#include <linux/regmap.h>
#include <linux/syscore_ops.h>
#include "clk.h"
@@ -21,19 +23,29 @@
static LIST_HEAD(clock_reg_cache_list);
void samsung_clk_save(void __iomem *base,
+ struct regmap *regmap,
struct samsung_clk_reg_dump *rd,
unsigned int num_regs)
{
- for (; num_regs > 0; --num_regs, ++rd)
- rd->value = readl(base + rd->offset);
+ for (; num_regs > 0; --num_regs, ++rd) {
+ if (base)
+ rd->value = readl(base + rd->offset);
+ else if (regmap)
+ regmap_read(regmap, rd->offset, &rd->value);
+ }
}
void samsung_clk_restore(void __iomem *base,
+ struct regmap *regmap,
const struct samsung_clk_reg_dump *rd,
unsigned int num_regs)
{
- for (; num_regs > 0; --num_regs, ++rd)
- writel(rd->value, base + rd->offset);
+ for (; num_regs > 0; --num_regs, ++rd) {
+ if (base)
+ writel(rd->value, base + rd->offset);
+ else if (regmap)
+ regmap_write(regmap, rd->offset, rd->value);
+ }
}
struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump(
@@ -227,6 +239,103 @@ void __init samsung_clk_register_div(struct samsung_clk_provider *ctx,
}
}
+/*
+ * Some older DT's have an incorrect CMU resource size which is incompatible
+ * with the auto clock mode feature. In such cases we switch back to manual
+ * clock gating mode.
+ */
+bool samsung_is_auto_capable(struct device_node *np)
+{
+ struct resource res;
+ resource_size_t size;
+
+ if (of_address_to_resource(np, 0, &res))
+ return false;
+
+ size = resource_size(&res);
+ if (size != 0x10000) {
+ pr_warn("%pOF: incorrect res size for automatic clocks\n", np);
+ return false;
+ }
+ return true;
+}
+
+#define ACG_MSK GENMASK(6, 4)
+#define CLK_IDLE GENMASK(5, 4)
+static int samsung_auto_clk_gate_is_en(struct clk_hw *hw)
+{
+ u32 reg;
+ struct clk_gate *gate = to_clk_gate(hw);
+
+ reg = readl(gate->reg);
+ return ((reg & ACG_MSK) == CLK_IDLE) ? 0 : 1;
+}
+
+/* enable and disable are nops in automatic clock mode */
+static int samsung_auto_clk_gate_en(struct clk_hw *hw)
+{
+ return 0;
+}
+
+static void samsung_auto_clk_gate_dis(struct clk_hw *hw)
+{
+}
+
+static const struct clk_ops samsung_auto_clk_gate_ops = {
+ .enable = samsung_auto_clk_gate_en,
+ .disable = samsung_auto_clk_gate_dis,
+ .is_enabled = samsung_auto_clk_gate_is_en,
+};
+
+struct clk_hw *samsung_register_auto_gate(struct device *dev,
+ struct device_node *np, const char *name,
+ const char *parent_name, const struct clk_hw *parent_hw,
+ const struct clk_parent_data *parent_data,
+ unsigned long flags,
+ void __iomem *reg, u8 bit_idx,
+ u8 clk_gate_flags, spinlock_t *lock)
+{
+ struct clk_gate *gate;
+ struct clk_hw *hw;
+ struct clk_init_data init = {};
+ int ret = -EINVAL;
+
+ /* allocate the gate */
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &samsung_auto_clk_gate_ops;
+ init.flags = flags;
+ init.parent_names = parent_name ? &parent_name : NULL;
+ init.parent_hws = parent_hw ? &parent_hw : NULL;
+ init.parent_data = parent_data;
+ if (parent_name || parent_hw || parent_data)
+ init.num_parents = 1;
+ else
+ init.num_parents = 0;
+
+ /* struct clk_gate assignments */
+ gate->reg = reg;
+ gate->bit_idx = bit_idx;
+ gate->flags = clk_gate_flags;
+ gate->lock = lock;
+ gate->hw.init = &init;
+
+ hw = &gate->hw;
+ if (dev || !np)
+ ret = clk_hw_register(dev, hw);
+ else if (np)
+ ret = of_clk_hw_register(np, hw);
+ if (ret) {
+ kfree(gate);
+ hw = ERR_PTR(ret);
+ }
+
+ return hw;
+}
+
/* register a list of gate clocks */
void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx,
const struct samsung_gate_clock *list,
@@ -234,14 +343,24 @@ void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx,
{
struct clk_hw *clk_hw;
unsigned int idx;
+ void __iomem *reg_offs;
for (idx = 0; idx < nr_clk; idx++, list++) {
- clk_hw = clk_hw_register_gate(ctx->dev, list->name, list->parent_name,
- list->flags, ctx->reg_base + list->offset,
+ reg_offs = ctx->reg_base + list->offset;
+
+ if (ctx->auto_clock_gate && ctx->gate_dbg_offset)
+ clk_hw = samsung_register_auto_gate(ctx->dev, NULL,
+ list->name, list->parent_name, NULL, NULL,
+ list->flags, reg_offs + ctx->gate_dbg_offset,
list->bit_idx, list->gate_flags, &ctx->lock);
+ else
+ clk_hw = clk_hw_register_gate(ctx->dev, list->name,
+ list->parent_name, list->flags,
+ ctx->reg_base + list->offset, list->bit_idx,
+ list->gate_flags, &ctx->lock);
if (IS_ERR(clk_hw)) {
- pr_err("%s: failed to register clock %s\n", __func__,
- list->name);
+ pr_err("%s: failed to register clock %s: %ld\n", __func__,
+ list->name, PTR_ERR(clk_hw));
continue;
}
@@ -276,10 +395,11 @@ static int samsung_clk_suspend(void)
struct samsung_clock_reg_cache *reg_cache;
list_for_each_entry(reg_cache, &clock_reg_cache_list, node) {
- samsung_clk_save(reg_cache->reg_base, reg_cache->rdump,
- reg_cache->rd_num);
- samsung_clk_restore(reg_cache->reg_base, reg_cache->rsuspend,
- reg_cache->rsuspend_num);
+ samsung_clk_save(reg_cache->reg_base, reg_cache->sysreg,
+ reg_cache->rdump, reg_cache->rd_num);
+ samsung_clk_restore(reg_cache->reg_base, reg_cache->sysreg,
+ reg_cache->rsuspend,
+ reg_cache->rsuspend_num);
}
return 0;
}
@@ -289,8 +409,8 @@ static void samsung_clk_resume(void)
struct samsung_clock_reg_cache *reg_cache;
list_for_each_entry(reg_cache, &clock_reg_cache_list, node)
- samsung_clk_restore(reg_cache->reg_base, reg_cache->rdump,
- reg_cache->rd_num);
+ samsung_clk_restore(reg_cache->reg_base, reg_cache->sysreg,
+ reg_cache->rdump, reg_cache->rd_num);
}
static struct syscore_ops samsung_clk_syscore_ops = {
@@ -299,6 +419,7 @@ static struct syscore_ops samsung_clk_syscore_ops = {
};
void samsung_clk_extended_sleep_init(void __iomem *reg_base,
+ struct regmap *sysreg,
const unsigned long *rdump,
unsigned long nr_rdump,
const struct samsung_clk_reg_dump *rsuspend,
@@ -319,6 +440,7 @@ void samsung_clk_extended_sleep_init(void __iomem *reg_base,
register_syscore_ops(&samsung_clk_syscore_ops);
reg_cache->reg_base = reg_base;
+ reg_cache->sysreg = sysreg;
reg_cache->rd_num = nr_rdump;
reg_cache->rsuspend = rsuspend;
reg_cache->rsuspend_num = nr_rsuspend;
@@ -330,10 +452,20 @@ void samsung_clk_extended_sleep_init(void __iomem *reg_base,
* samsung_cmu_register_clocks() - Register all clocks provided in CMU object
* @ctx: Clock provider object
* @cmu: CMU object with clocks to register
+ * @np: CMU device tree node
*/
void __init samsung_cmu_register_clocks(struct samsung_clk_provider *ctx,
- const struct samsung_cmu_info *cmu)
+ const struct samsung_cmu_info *cmu,
+ struct device_node *np)
{
+ if (samsung_is_auto_capable(np) && cmu->auto_clock_gate)
+ ctx->auto_clock_gate = cmu->auto_clock_gate;
+
+ ctx->gate_dbg_offset = cmu->gate_dbg_offset;
+ ctx->option_offset = cmu->option_offset;
+ ctx->drcg_offset = cmu->drcg_offset;
+ ctx->memclk_offset = cmu->memclk_offset;
+
if (cmu->pll_clks)
samsung_clk_register_pll(ctx, cmu->pll_clks, cmu->nr_pll_clks);
if (cmu->mux_clks)
@@ -353,6 +485,37 @@ void __init samsung_cmu_register_clocks(struct samsung_clk_provider *ctx,
samsung_clk_register_cpu(ctx, cmu->cpu_clks, cmu->nr_cpu_clks);
}
+/* Each bit enable/disables DRCG of a bus component */
+#define DRCG_EN_MSK GENMASK(31, 0)
+#define MEMCLK_EN BIT(0)
+
+/* Enable Dynamic Root Clock Gating (DRCG) of bus components */
+void samsung_en_dyn_root_clk_gating(struct device_node *np,
+ struct samsung_clk_provider *ctx,
+ const struct samsung_cmu_info *cmu)
+{
+ if (!ctx->auto_clock_gate)
+ return;
+
+ ctx->sysreg = syscon_regmap_lookup_by_phandle(np, "samsung,sysreg");
+ if (IS_ERR(ctx->sysreg)) {
+ pr_warn("%pOF: Unable to get CMU sysreg\n", np);
+ ctx->sysreg = NULL;
+ } else {
+ /* Enable DRCG for all bus components */
+ regmap_write(ctx->sysreg, ctx->drcg_offset, DRCG_EN_MSK);
+ /* Enable memclk gate (not present on all sysreg) */
+ if (ctx->memclk_offset)
+ regmap_write_bits(ctx->sysreg, ctx->memclk_offset,
+ MEMCLK_EN, 0x0);
+
+ samsung_clk_extended_sleep_init(NULL, ctx->sysreg,
+ cmu->sysreg_clk_regs,
+ cmu->nr_sysreg_clk_regs,
+ NULL, 0);
+ }
+}
+
/*
* Common function which registers plls, muxes, dividers and gates
* for each CMU. It also add CMU register list to register cache.
@@ -371,14 +534,17 @@ struct samsung_clk_provider * __init samsung_cmu_register_one(
}
ctx = samsung_clk_init(NULL, reg_base, cmu->nr_clk_ids);
- samsung_cmu_register_clocks(ctx, cmu);
+ samsung_cmu_register_clocks(ctx, cmu, np);
if (cmu->clk_regs)
- samsung_clk_extended_sleep_init(reg_base,
+ samsung_clk_extended_sleep_init(reg_base, NULL,
cmu->clk_regs, cmu->nr_clk_regs,
cmu->suspend_regs, cmu->nr_suspend_regs);
samsung_clk_of_add_provider(np, ctx);
+ /* sysreg DT nodes reference a clock in this CMU */
+ samsung_en_dyn_root_clk_gating(np, ctx, cmu);
+
return ctx;
}
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index 18660c1ac6f0106b17b9efc9c6b3cd62d46f7b82..a56aa3be54d817cd24bf2bc29427e783a1a9a859 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -12,6 +12,7 @@
#include <linux/clk-provider.h>
#include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
#include "clk-pll.h"
#include "clk-cpu.h"
@@ -19,13 +20,25 @@
* struct samsung_clk_provider - information about clock provider
* @reg_base: virtual address for the register base
* @dev: clock provider device needed for runtime PM
+ * @sysreg: syscon regmap for clock-provider sysreg controller
* @lock: maintains exclusion between callbacks for a given clock-provider
+ * @auto_clock_gate: enable auto clk mode for all clocks in clock-provider
+ * @gate_dbg_offset: gate debug reg offset. Used for all gates in auto clk mode
+ * @option_offset: option reg offset. Enables auto mode for clock-provider
+ * @drcg_offset: dynamic root clk gate enable register offset in sysreg
+ * @memclk_offset: memclk enable register offset in sysreg
* @clk_data: holds clock related data like clk_hw* and number of clocks
*/
struct samsung_clk_provider {
void __iomem *reg_base;
struct device *dev;
+ struct regmap *sysreg;
spinlock_t lock;
+ bool auto_clock_gate;
+ u32 gate_dbg_offset;
+ u32 option_offset;
+ u32 drcg_offset;
+ u32 memclk_offset;
/* clk_data must be the last entry due to variable length 'hws' array */
struct clk_hw_onecell_data clk_data;
};
@@ -310,6 +323,7 @@ struct samsung_cpu_clock {
struct samsung_clock_reg_cache {
struct list_head node;
void __iomem *reg_base;
+ struct regmap *sysreg;
struct samsung_clk_reg_dump *rdump;
unsigned int rd_num;
const struct samsung_clk_reg_dump *rsuspend;
@@ -338,7 +352,14 @@ struct samsung_clock_reg_cache {
* @suspend_regs: list of clock registers to set before suspend
* @nr_suspend_regs: count of clock registers in @suspend_regs
* @clk_name: name of the parent clock needed for CMU register access
+ * @sysreg_clk_regs: list of sysreg clock registers
+ * @nr_sysreg_clk_regs: count of clock registers in @sysreg_clk_regs
* @manual_plls: Enable manual control for PLL clocks
+ * @auto_clock_gate: enable auto clock mode for all components in CMU
+ * @gate_dbg_offset: gate debug reg offset. Used by all gates in auto clk mode
+ * @option_offset: option reg offset. Enables auto clk mode for entire CMU
+ * @drcg_offset: dynamic root clk gate enable register offset in sysreg
+ * @memclk_offset: memclk enable register offset in sysreg
*/
struct samsung_cmu_info {
const struct samsung_pll_clock *pll_clks;
@@ -364,8 +385,16 @@ struct samsung_cmu_info {
unsigned int nr_suspend_regs;
const char *clk_name;
+ const unsigned long *sysreg_clk_regs;
+ unsigned int nr_sysreg_clk_regs;
+
/* ARM64 Exynos CMUs */
bool manual_plls;
+ bool auto_clock_gate;
+ u32 gate_dbg_offset;
+ u32 option_offset;
+ u32 drcg_offset;
+ u32 memclk_offset;
};
struct samsung_clk_provider *samsung_clk_init(struct device *dev,
@@ -408,35 +437,55 @@ void samsung_clk_register_cpu(struct samsung_clk_provider *ctx,
const struct samsung_cpu_clock *list, unsigned int nr_clk);
void samsung_cmu_register_clocks(struct samsung_clk_provider *ctx,
- const struct samsung_cmu_info *cmu);
+ const struct samsung_cmu_info *cmu,
+ struct device_node *np);
struct samsung_clk_provider *samsung_cmu_register_one(
struct device_node *,
const struct samsung_cmu_info *);
#ifdef CONFIG_PM_SLEEP
void samsung_clk_extended_sleep_init(void __iomem *reg_base,
+ struct regmap *sysreg,
const unsigned long *rdump,
unsigned long nr_rdump,
const struct samsung_clk_reg_dump *rsuspend,
unsigned long nr_rsuspend);
#else
static inline void samsung_clk_extended_sleep_init(void __iomem *reg_base,
+ struct regmap *sysreg,
const unsigned long *rdump,
unsigned long nr_rdump,
const struct samsung_clk_reg_dump *rsuspend,
unsigned long nr_rsuspend) {}
#endif
-#define samsung_clk_sleep_init(reg_base, rdump, nr_rdump) \
- samsung_clk_extended_sleep_init(reg_base, rdump, nr_rdump, NULL, 0)
+#define samsung_clk_sleep_init(reg_base, sysreg, rdump, nr_rdump) \
+ samsung_clk_extended_sleep_init(reg_base, sysreg, rdump, nr_rdump, \
+ NULL, 0)
void samsung_clk_save(void __iomem *base,
+ struct regmap *regmap,
struct samsung_clk_reg_dump *rd,
unsigned int num_regs);
void samsung_clk_restore(void __iomem *base,
+ struct regmap *regmap,
const struct samsung_clk_reg_dump *rd,
unsigned int num_regs);
struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump(
const unsigned long *rdump,
unsigned long nr_rdump);
+void samsung_en_dyn_root_clk_gating(struct device_node *np,
+ struct samsung_clk_provider *ctx,
+ const struct samsung_cmu_info *cmu);
+
+struct clk_hw *samsung_register_auto_gate(struct device *dev,
+ struct device_node *np, const char *name,
+ const char *parent_name, const struct clk_hw *parent_hw,
+ const struct clk_parent_data *parent_data,
+ unsigned long flags,
+ void __iomem *reg, u8 bit_idx,
+ u8 clk_gate_flags, spinlock_t *lock);
+
+bool samsung_is_auto_capable(struct device_node *np);
+
#endif /* __SAMSUNG_CLK_H */
--
2.51.2.1041.gc1ab5b90ca-goog
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v4 4/4] clk: samsung: gs101: Enable auto_clock_gate mode for each gs101 CMU
2025-11-10 14:21 [PATCH v4 0/4] Implement hardware automatic clock gating (HWACG) for gs101 Peter Griffin
` (2 preceding siblings ...)
2025-11-10 14:21 ` [PATCH v4 3/4] clk: samsung: Implement automatic clock gating mode for CMUs Peter Griffin
@ 2025-11-10 14:21 ` Peter Griffin
3 siblings, 0 replies; 8+ messages in thread
From: Peter Griffin @ 2025-11-10 14:21 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Alim Akhtar,
André Draszik, Tudor Ambarus, Michael Turquette,
Stephen Boyd, Sam Protsenko, Sylwester Nawrocki, Chanwoo Choi
Cc: Will McVicker, Krzysztof Kozlowski, devicetree, linux-arm-kernel,
linux-samsung-soc, linux-kernel, linux-clk, kernel-team,
Peter Griffin, Krzysztof Kozlowski
Enable auto clock mode, and define the additional fields which are used
when this mode is enabled.
/sys/kernel/debug/clk/clk_summary now reports approximately 308 running
clocks and 298 disabled clocks. Prior to this commit 586 clocks were
running and 17 disabled.
Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
---
Changes in v4:
- Remove unnecessary header of_address.h (Peter)
---
drivers/clk/samsung/clk-gs101.c | 55 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 55 insertions(+)
diff --git a/drivers/clk/samsung/clk-gs101.c b/drivers/clk/samsung/clk-gs101.c
index 70b26db9b95ad0b376d23f637c7683fbc8c8c600..8551289b46eb88ec61dd1914d0fe782ae6794000 100644
--- a/drivers/clk/samsung/clk-gs101.c
+++ b/drivers/clk/samsung/clk-gs101.c
@@ -26,6 +26,10 @@
#define CLKS_NR_PERIC0 (CLK_GOUT_PERIC0_SYSREG_PERIC0_PCLK + 1)
#define CLKS_NR_PERIC1 (CLK_GOUT_PERIC1_SYSREG_PERIC1_PCLK + 1)
+#define GS101_GATE_DBG_OFFSET 0x4000
+#define GS101_DRCG_EN_OFFSET 0x104
+#define GS101_MEMCLK_OFFSET 0x108
+
/* ---- CMU_TOP ------------------------------------------------------------- */
/* Register Offset definitions for CMU_TOP (0x1e080000) */
@@ -1433,6 +1437,9 @@ static const struct samsung_cmu_info top_cmu_info __initconst = {
.nr_clk_ids = CLKS_NR_TOP,
.clk_regs = cmu_top_clk_regs,
.nr_clk_regs = ARRAY_SIZE(cmu_top_clk_regs),
+ .auto_clock_gate = true,
+ .gate_dbg_offset = GS101_GATE_DBG_OFFSET,
+ .option_offset = CMU_CMU_TOP_CONTROLLER_OPTION,
};
static void __init gs101_cmu_top_init(struct device_node *np)
@@ -1900,6 +1907,11 @@ static const struct samsung_gate_clock apm_gate_clks[] __initconst = {
CLK_CON_GAT_GOUT_BLK_APM_UID_XIU_DP_APM_IPCLKPORT_ACLK, 21, CLK_IS_CRITICAL, 0),
};
+static const unsigned long dcrg_memclk_sysreg[] __initconst = {
+ GS101_DRCG_EN_OFFSET,
+ GS101_MEMCLK_OFFSET,
+};
+
static const struct samsung_cmu_info apm_cmu_info __initconst = {
.mux_clks = apm_mux_clks,
.nr_mux_clks = ARRAY_SIZE(apm_mux_clks),
@@ -1912,6 +1924,12 @@ static const struct samsung_cmu_info apm_cmu_info __initconst = {
.nr_clk_ids = CLKS_NR_APM,
.clk_regs = apm_clk_regs,
.nr_clk_regs = ARRAY_SIZE(apm_clk_regs),
+ .sysreg_clk_regs = dcrg_memclk_sysreg,
+ .nr_sysreg_clk_regs = ARRAY_SIZE(dcrg_memclk_sysreg),
+ .auto_clock_gate = true,
+ .gate_dbg_offset = GS101_GATE_DBG_OFFSET,
+ .drcg_offset = GS101_DRCG_EN_OFFSET,
+ .memclk_offset = GS101_MEMCLK_OFFSET,
};
/* ---- CMU_HSI0 ------------------------------------------------------------ */
@@ -2375,7 +2393,14 @@ static const struct samsung_cmu_info hsi0_cmu_info __initconst = {
.nr_clk_ids = CLKS_NR_HSI0,
.clk_regs = hsi0_clk_regs,
.nr_clk_regs = ARRAY_SIZE(hsi0_clk_regs),
+ .sysreg_clk_regs = dcrg_memclk_sysreg,
+ .nr_sysreg_clk_regs = ARRAY_SIZE(dcrg_memclk_sysreg),
.clk_name = "bus",
+ .auto_clock_gate = true,
+ .gate_dbg_offset = GS101_GATE_DBG_OFFSET,
+ .option_offset = HSI0_CMU_HSI0_CONTROLLER_OPTION,
+ .drcg_offset = GS101_DRCG_EN_OFFSET,
+ .memclk_offset = GS101_MEMCLK_OFFSET,
};
/* ---- CMU_HSI2 ------------------------------------------------------------ */
@@ -2863,7 +2888,14 @@ static const struct samsung_cmu_info hsi2_cmu_info __initconst = {
.nr_clk_ids = CLKS_NR_HSI2,
.clk_regs = cmu_hsi2_clk_regs,
.nr_clk_regs = ARRAY_SIZE(cmu_hsi2_clk_regs),
+ .sysreg_clk_regs = dcrg_memclk_sysreg,
+ .nr_sysreg_clk_regs = ARRAY_SIZE(dcrg_memclk_sysreg),
.clk_name = "bus",
+ .auto_clock_gate = true,
+ .gate_dbg_offset = GS101_GATE_DBG_OFFSET,
+ .option_offset = HSI2_CMU_HSI2_CONTROLLER_OPTION,
+ .drcg_offset = GS101_DRCG_EN_OFFSET,
+ .memclk_offset = GS101_MEMCLK_OFFSET,
};
/* ---- CMU_MISC ------------------------------------------------------------ */
@@ -3423,7 +3455,14 @@ static const struct samsung_cmu_info misc_cmu_info __initconst = {
.nr_clk_ids = CLKS_NR_MISC,
.clk_regs = misc_clk_regs,
.nr_clk_regs = ARRAY_SIZE(misc_clk_regs),
+ .sysreg_clk_regs = dcrg_memclk_sysreg,
+ .nr_sysreg_clk_regs = ARRAY_SIZE(dcrg_memclk_sysreg),
.clk_name = "bus",
+ .auto_clock_gate = true,
+ .gate_dbg_offset = GS101_GATE_DBG_OFFSET,
+ .option_offset = MISC_CMU_MISC_CONTROLLER_OPTION,
+ .drcg_offset = GS101_DRCG_EN_OFFSET,
+ .memclk_offset = GS101_MEMCLK_OFFSET,
};
static void __init gs101_cmu_misc_init(struct device_node *np)
@@ -4010,6 +4049,10 @@ static const struct samsung_gate_clock peric0_gate_clks[] __initconst = {
21, 0, 0),
};
+static const unsigned long dcrg_sysreg[] __initconst = {
+ GS101_DRCG_EN_OFFSET,
+};
+
static const struct samsung_cmu_info peric0_cmu_info __initconst = {
.mux_clks = peric0_mux_clks,
.nr_mux_clks = ARRAY_SIZE(peric0_mux_clks),
@@ -4020,7 +4063,13 @@ static const struct samsung_cmu_info peric0_cmu_info __initconst = {
.nr_clk_ids = CLKS_NR_PERIC0,
.clk_regs = peric0_clk_regs,
.nr_clk_regs = ARRAY_SIZE(peric0_clk_regs),
+ .sysreg_clk_regs = dcrg_sysreg,
+ .nr_sysreg_clk_regs = ARRAY_SIZE(dcrg_sysreg),
.clk_name = "bus",
+ .auto_clock_gate = true,
+ .gate_dbg_offset = GS101_GATE_DBG_OFFSET,
+ .option_offset = PERIC0_CMU_PERIC0_CONTROLLER_OPTION,
+ .drcg_offset = GS101_DRCG_EN_OFFSET,
};
/* ---- CMU_PERIC1 ---------------------------------------------------------- */
@@ -4368,7 +4417,13 @@ static const struct samsung_cmu_info peric1_cmu_info __initconst = {
.nr_clk_ids = CLKS_NR_PERIC1,
.clk_regs = peric1_clk_regs,
.nr_clk_regs = ARRAY_SIZE(peric1_clk_regs),
+ .sysreg_clk_regs = dcrg_sysreg,
+ .nr_sysreg_clk_regs = ARRAY_SIZE(dcrg_sysreg),
.clk_name = "bus",
+ .auto_clock_gate = true,
+ .gate_dbg_offset = GS101_GATE_DBG_OFFSET,
+ .option_offset = PERIC1_CMU_PERIC1_CONTROLLER_OPTION,
+ .drcg_offset = GS101_DRCG_EN_OFFSET,
};
/* ---- platform_driver ----------------------------------------------------- */
--
2.51.2.1041.gc1ab5b90ca-goog
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v4 1/4] dt-bindings: clock: google,gs101-clock: add samsung,sysreg property as required
2025-11-10 14:21 ` [PATCH v4 1/4] dt-bindings: clock: google,gs101-clock: add samsung,sysreg property as required Peter Griffin
@ 2025-11-11 9:54 ` André Draszik
2025-11-11 9:57 ` André Draszik
0 siblings, 1 reply; 8+ messages in thread
From: André Draszik @ 2025-11-11 9:54 UTC (permalink / raw)
To: Peter Griffin, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Alim Akhtar, Tudor Ambarus, Michael Turquette, Stephen Boyd,
Sam Protsenko, Sylwester Nawrocki, Chanwoo Choi
Cc: Will McVicker, Krzysztof Kozlowski, devicetree, linux-arm-kernel,
linux-samsung-soc, linux-kernel, linux-clk, kernel-team
Hi Peter,
On Mon, 2025-11-10 at 14:21 +0000, Peter Griffin wrote:
> [...]
>
> diff --git a/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml b/Documentation/devicetree/bindings/clock/google,gs101-
> clock.yaml
> index 31e106ef913dead9a038b3b6d8b43b950587f6aa..5ce5ba523110af3a2a7740b8ba28e2271c76bddb 100644
> --- a/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
> +++ b/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
> @@ -52,6 +52,11 @@ properties:
> reg:
> maxItems: 1
>
> + samsung,sysreg:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description:
> + Phandle to system registers interface.
> +
> required:
> - compatible
> - "#clock-cells"
> @@ -166,6 +171,22 @@ allOf:
> - const: bus
> - const: ip
>
> + - if:
> + properties:
> + compatible:
> + contains:
> + enum:
> + - google,gs101-cmu-apm
> + - google,gs101-cmu-misc
> + - google,gs101-hsi0
Shouldn't this be google,gs101-cmu-hsi0?
> + - google,gs101-cmu-hsi2
> + - google,gs101-cmu-peric0
> + - google,gs101-cmu-peric1
> +
> + then:
> + required:
> + - samsung,sysreg
The above still allows (but doesn't enforce) samsung,sysreg on cmu-top.
Maybe it'd be better to invert the test, as cmu-top is the only
outlier, and then the binding doesn't need to be updated when more
CMUs are added (untested):
- if:
properties:
compatible:
contains:
const: google,gs101-cmu-top
then:
required:
- samsung,sysreg
else:
properties:
samsung,sysreg: false
Cheers,
Andre'
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v4 1/4] dt-bindings: clock: google,gs101-clock: add samsung,sysreg property as required
2025-11-11 9:54 ` André Draszik
@ 2025-11-11 9:57 ` André Draszik
2025-11-14 14:15 ` Peter Griffin
0 siblings, 1 reply; 8+ messages in thread
From: André Draszik @ 2025-11-11 9:57 UTC (permalink / raw)
To: Peter Griffin, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Alim Akhtar, Tudor Ambarus, Michael Turquette, Stephen Boyd,
Sam Protsenko, Sylwester Nawrocki, Chanwoo Choi
Cc: Will McVicker, Krzysztof Kozlowski, devicetree, linux-arm-kernel,
linux-samsung-soc, linux-kernel, linux-clk, kernel-team
On Tue, 2025-11-11 at 09:54 +0000, André Draszik wrote:
> Hi Peter,
>
> On Mon, 2025-11-10 at 14:21 +0000, Peter Griffin wrote:
> > [...]
> >
> > diff --git a/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
> > b/Documentation/devicetree/bindings/clock/google,gs101-
> > clock.yaml
> > index 31e106ef913dead9a038b3b6d8b43b950587f6aa..5ce5ba523110af3a2a7740b8ba28e2271c76bddb 100644
> > --- a/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
> > +++ b/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
> > @@ -52,6 +52,11 @@ properties:
> > reg:
> > maxItems: 1
> >
> > + samsung,sysreg:
> > + $ref: /schemas/types.yaml#/definitions/phandle
> > + description:
> > + Phandle to system registers interface.
> > +
> > required:
> > - compatible
> > - "#clock-cells"
> > @@ -166,6 +171,22 @@ allOf:
> > - const: bus
> > - const: ip
> >
> > + - if:
> > + properties:
> > + compatible:
> > + contains:
> > + enum:
> > + - google,gs101-cmu-apm
> > + - google,gs101-cmu-misc
> > + - google,gs101-hsi0
>
> Shouldn't this be google,gs101-cmu-hsi0?
>
> > + - google,gs101-cmu-hsi2
> > + - google,gs101-cmu-peric0
> > + - google,gs101-cmu-peric1
> > +
> > + then:
> > + required:
> > + - samsung,sysreg
>
> The above still allows (but doesn't enforce) samsung,sysreg on cmu-top.
>
> Maybe it'd be better to invert the test, as cmu-top is the only
> outlier, and then the binding doesn't need to be updated when more
> CMUs are added (untested):
>
> - if:
> properties:
> compatible:
> contains:
> const: google,gs101-cmu-top
>
> then:
> required:
> - samsung,sysreg
>
> else:
> properties:
> samsung,sysreg: false
obviously then: and else: cases should be swapped.
A.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v4 1/4] dt-bindings: clock: google,gs101-clock: add samsung,sysreg property as required
2025-11-11 9:57 ` André Draszik
@ 2025-11-14 14:15 ` Peter Griffin
0 siblings, 0 replies; 8+ messages in thread
From: Peter Griffin @ 2025-11-14 14:15 UTC (permalink / raw)
To: André Draszik
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Alim Akhtar,
Tudor Ambarus, Michael Turquette, Stephen Boyd, Sam Protsenko,
Sylwester Nawrocki, Chanwoo Choi, Will McVicker,
Krzysztof Kozlowski, devicetree, linux-arm-kernel,
linux-samsung-soc, linux-kernel, linux-clk, kernel-team
Hi André,
Thanks for the review feedback!
On Tue, 11 Nov 2025 at 09:57, André Draszik <andre.draszik@linaro.org> wrote:
>
> On Tue, 2025-11-11 at 09:54 +0000, André Draszik wrote:
> > Hi Peter,
> >
> > On Mon, 2025-11-10 at 14:21 +0000, Peter Griffin wrote:
> > > [...]
> > >
> > > diff --git a/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
> > > b/Documentation/devicetree/bindings/clock/google,gs101-
> > > clock.yaml
> > > index 31e106ef913dead9a038b3b6d8b43b950587f6aa..5ce5ba523110af3a2a7740b8ba28e2271c76bddb 100644
> > > --- a/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
> > > +++ b/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml
> > > @@ -52,6 +52,11 @@ properties:
> > > reg:
> > > maxItems: 1
> > >
> > > + samsung,sysreg:
> > > + $ref: /schemas/types.yaml#/definitions/phandle
> > > + description:
> > > + Phandle to system registers interface.
> > > +
> > > required:
> > > - compatible
> > > - "#clock-cells"
> > > @@ -166,6 +171,22 @@ allOf:
> > > - const: bus
> > > - const: ip
> > >
> > > + - if:
> > > + properties:
> > > + compatible:
> > > + contains:
> > > + enum:
> > > + - google,gs101-cmu-apm
> > > + - google,gs101-cmu-misc
> > > + - google,gs101-hsi0
> >
> > Shouldn't this be google,gs101-cmu-hsi0?
> >
> > > + - google,gs101-cmu-hsi2
> > > + - google,gs101-cmu-peric0
> > > + - google,gs101-cmu-peric1
> > > +
> > > + then:
> > > + required:
> > > + - samsung,sysreg
> >
> > The above still allows (but doesn't enforce) samsung,sysreg on cmu-top.
> >
> > Maybe it'd be better to invert the test, as cmu-top is the only
> > outlier, and then the binding doesn't need to be updated when more
> > CMUs are added (untested):
> >
> > - if:
> > properties:
> > compatible:
> > contains:
> > const: google,gs101-cmu-top
> >
> > then:
> > required:
> > - samsung,sysreg
> >
> > else:
> > properties:
> > samsung,sysreg: false
>
> obviously then: and else: cases should be swapped.
I'll send an updated version with these suggestions integrated in a moment.
Thanks,
Peter
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2025-11-14 14:16 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-10 14:21 [PATCH v4 0/4] Implement hardware automatic clock gating (HWACG) for gs101 Peter Griffin
2025-11-10 14:21 ` [PATCH v4 1/4] dt-bindings: clock: google,gs101-clock: add samsung,sysreg property as required Peter Griffin
2025-11-11 9:54 ` André Draszik
2025-11-11 9:57 ` André Draszik
2025-11-14 14:15 ` Peter Griffin
2025-11-10 14:21 ` [PATCH v4 2/4] arm64: dts: exynos: gs101: add samsung,sysreg property to CMU nodes Peter Griffin
2025-11-10 14:21 ` [PATCH v4 3/4] clk: samsung: Implement automatic clock gating mode for CMUs Peter Griffin
2025-11-10 14:21 ` [PATCH v4 4/4] clk: samsung: gs101: Enable auto_clock_gate mode for each gs101 CMU Peter Griffin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).