2023-03-08 23:38:33

by Sam Protsenko

[permalink] [raw]
Subject: [PATCH 0/7] clk: samsung: Enable PM in Exynos850 clk driver

One difference Exynos850 has w.r.t. other Exynos platforms in terms of
PM is that EL3 monitor handles TZ protection of CMU domains on
suspend/resume for us. This series enables PM support in clk-exynos850,
which was originally borrowed/extracted from clk-exynos5433 driver, and
also adds other missing bits, like adding those SMC calls, keeping PMU
clock always enabled and configuring MUX clocks before the suspend.

Dependencies inside of this series:

- patch #7 must go after #4
- patches 3-6 should go in the same order as in the series
- better to keep patche #1 and #2 before the rest of patches,
so that the driver and dts always use documented properties

Sam Protsenko (7):
dt-bindings: clock: exynos850: Add power-domains property
dt-bindings: clock: exynos850: Add tzpc property
clk: samsung: Implement PM SMC calls for ARM64 Exynos SoCs
clk: samsung: exynos850: Make PMU_ALIVE_PCLK critical
clk: samsung: exynos850: Add suspend state for all CMUs
clk: samsung: exynos850: Enable PM support in clk-exynos850
arm64: dts: exynos: Remove clock from Exynos850 pmu_system_controller

.../clock/samsung,exynos850-clock.yaml | 13 ++
arch/arm64/boot/dts/exynos/exynos850.dtsi | 1 -
drivers/clk/samsung/clk-exynos-arm64.c | 39 +++++-
drivers/clk/samsung/clk-exynos850.c | 112 ++++++++++++++++--
4 files changed, 153 insertions(+), 12 deletions(-)

--
2.39.2



2023-03-08 23:38:38

by Sam Protsenko

[permalink] [raw]
Subject: [PATCH 1/7] dt-bindings: clock: exynos850: Add power-domains property

Document power-domains property in Exynos850 clock controller.

Signed-off-by: Sam Protsenko <[email protected]>
---
.../devicetree/bindings/clock/samsung,exynos850-clock.yaml | 3 +++
1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/samsung,exynos850-clock.yaml b/Documentation/devicetree/bindings/clock/samsung,exynos850-clock.yaml
index 8aa87b8c1b33..cc1e9173b272 100644
--- a/Documentation/devicetree/bindings/clock/samsung,exynos850-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/samsung,exynos850-clock.yaml
@@ -54,6 +54,9 @@ properties:
"#clock-cells":
const: 1

+ power-domains:
+ maxItems: 1
+
reg:
maxItems: 1

--
2.39.2


2023-03-08 23:38:42

by Sam Protsenko

[permalink] [raw]
Subject: [PATCH 2/7] dt-bindings: clock: exynos850: Add tzpc property

Exynos850 requires extra TZPC handling to keep CMU registers non-secure
(accessible from the kernel) after PM resume. It's done using a specific
SMC call to the EL3 monitor.

Describe "samsung,tzpc" property for Exynos850 clock controller which
allows one to specify the SMC call address for PD capable CMUs.

Signed-off-by: Sam Protsenko <[email protected]>
---
.../bindings/clock/samsung,exynos850-clock.yaml | 10 ++++++++++
1 file changed, 10 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/samsung,exynos850-clock.yaml b/Documentation/devicetree/bindings/clock/samsung,exynos850-clock.yaml
index cc1e9173b272..5098dce5caf6 100644
--- a/Documentation/devicetree/bindings/clock/samsung,exynos850-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/samsung,exynos850-clock.yaml
@@ -60,6 +60,16 @@ properties:
reg:
maxItems: 1

+ samsung,tzpc:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ The register address in corresponding Trust Zone Protection Control block
+ for setting the CMU registers access to non-secure. If provided, it'll be
+ used for issuing SMC calls to EL3 monitor during CMU's PM suspend and
+ resume operations, ensuring CMU registers are unprotected after waking up.
+
+ This property is optional.
+
allOf:
- if:
properties:
--
2.39.2


2023-03-08 23:38:47

by Sam Protsenko

[permalink] [raw]
Subject: [PATCH 3/7] clk: samsung: Implement PM SMC calls for ARM64 Exynos SoCs

Exynos850 requires extra TZPC handling to keep CMU registers non-secure
(accessible from the kernel) after PM resume. It's done using a specific
SMC call to the EL3 monitor. Implement corresponding SMC calls in
suspend and resume functions. Perform those calls when the parent (bus)
clock is running to avoid SMC freezes. The "samsung,tzpc" property is
used to specify the TZPC register address for those calls (for each
particular domain). If that property is not provided, SMC calls won't be
performed, thus keeping the compatibility with CMUs and platforms where
that SMC functionality is not needed.

Signed-off-by: Sam Protsenko <[email protected]>
---
drivers/clk/samsung/clk-exynos-arm64.c | 39 ++++++++++++++++++++++++--
1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/samsung/clk-exynos-arm64.c b/drivers/clk/samsung/clk-exynos-arm64.c
index 7d8937caf22a..57e9bee7ec4d 100644
--- a/drivers/clk/samsung/clk-exynos-arm64.c
+++ b/drivers/clk/samsung/clk-exynos-arm64.c
@@ -8,6 +8,8 @@
* This file contains shared functions used by some arm64 Exynos SoCs,
* such as Exynos7885 or Exynos850 to register and init CMUs.
*/
+
+#include <linux/arm-smccc.h>
#include <linux/clk.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
@@ -24,6 +26,12 @@
#define GATE_OFF_START 0x2000
#define GATE_OFF_END 0x2fff

+/* Power control SMC command and its parameters */
+#define SMC_CMD_PREPARE_PD_ONOFF 0x82000410
+#define EXYNOS_PD_RUNTIME_PM 2
+#define EXYNOS_GET_IN_PD_DOWN 0
+#define EXYNOS_WAKEUP_PD_DOWN 1
+
struct exynos_arm64_cmu_data {
struct samsung_clk_reg_dump *clk_save;
unsigned int nr_clk_save;
@@ -34,6 +42,7 @@ struct exynos_arm64_cmu_data {
struct clk **pclks;
int nr_pclks;

+ unsigned int tzpc_addr; /* address for PM SMC calls */
struct samsung_clk_provider *ctx;
};

@@ -149,6 +158,22 @@ static int __init exynos_arm64_cmu_prepare_pm(struct device *dev,
return 0;
}

+static int exynos_arm64_pm_smc(struct device *dev, bool on)
+{
+ struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev);
+ struct arm_smccc_res res;
+ unsigned int pm_arg;
+
+ if (!data->tzpc_addr)
+ return 0;
+
+ pm_arg = on ? EXYNOS_WAKEUP_PD_DOWN : EXYNOS_GET_IN_PD_DOWN;
+ arm_smccc_smc(SMC_CMD_PREPARE_PD_ONOFF, pm_arg, data->tzpc_addr,
+ EXYNOS_PD_RUNTIME_PM, 0, 0, 0, 0, &res);
+
+ return res.a0;
+}
+
/**
* exynos_arm64_register_cmu - Register specified Exynos CMU domain
* @dev: Device object; may be NULL if this function is not being
@@ -207,6 +232,8 @@ int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev,
if (!data)
return -ENOMEM;

+ of_property_read_u32(np, "samsung,tzpc", (u32 *)&data->tzpc_addr);
+
platform_set_drvdata(pdev, data);

ret = exynos_arm64_cmu_prepare_pm(dev, cmu);
@@ -251,7 +278,7 @@ int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev,
int exynos_arm64_cmu_suspend(struct device *dev)
{
struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev);
- int i;
+ int i, ret;

samsung_clk_save(data->ctx->reg_base, data->clk_save,
data->nr_clk_save);
@@ -263,6 +290,10 @@ int exynos_arm64_cmu_suspend(struct device *dev)
samsung_clk_restore(data->ctx->reg_base, data->clk_suspend,
data->nr_clk_suspend);

+ ret = exynos_arm64_pm_smc(dev, false);
+ if (ret)
+ return ret;
+
for (i = 0; i < data->nr_pclks; i++)
clk_disable_unprepare(data->pclks[i]);

@@ -274,13 +305,17 @@ int exynos_arm64_cmu_suspend(struct device *dev)
int exynos_arm64_cmu_resume(struct device *dev)
{
struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev);
- int i;
+ int i, ret;

clk_prepare_enable(data->clk);

for (i = 0; i < data->nr_pclks; i++)
clk_prepare_enable(data->pclks[i]);

+ ret = exynos_arm64_pm_smc(dev, true);
+ if (ret)
+ return ret;
+
samsung_clk_restore(data->ctx->reg_base, data->clk_save,
data->nr_clk_save);

--
2.39.2


2023-03-08 23:38:51

by Sam Protsenko

[permalink] [raw]
Subject: [PATCH 4/7] clk: samsung: exynos850: Make PMU_ALIVE_PCLK critical

PMU_ALIVE_PCLK is needed for PMU registers access, and it must be always
running, as not only the kernel accesses PMU registers. Make it critical
to ensure that.

Signed-off-by: Sam Protsenko <[email protected]>
---
drivers/clk/samsung/clk-exynos850.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/clk/samsung/clk-exynos850.c b/drivers/clk/samsung/clk-exynos850.c
index 6ab5fa8c2ef3..98b23af7324d 100644
--- a/drivers/clk/samsung/clk-exynos850.c
+++ b/drivers/clk/samsung/clk-exynos850.c
@@ -612,7 +612,7 @@ static const struct samsung_gate_clock apm_gate_clks[] __initconst = {
CLK_CON_GAT_GOUT_APM_APBIF_GPIO_ALIVE_PCLK, 21, CLK_IGNORE_UNUSED,
0),
GATE(CLK_GOUT_PMU_ALIVE_PCLK, "gout_pmu_alive_pclk", "dout_apm_bus",
- CLK_CON_GAT_GOUT_APM_APBIF_PMU_ALIVE_PCLK, 21, 0, 0),
+ CLK_CON_GAT_GOUT_APM_APBIF_PMU_ALIVE_PCLK, 21, CLK_IS_CRITICAL, 0),
GATE(CLK_GOUT_SYSREG_APM_PCLK, "gout_sysreg_apm_pclk", "dout_apm_bus",
CLK_CON_GAT_GOUT_APM_SYSREG_APM_PCLK, 21, 0, 0),
};
--
2.39.2


2023-03-08 23:38:54

by Sam Protsenko

[permalink] [raw]
Subject: [PATCH 5/7] clk: samsung: exynos850: Add suspend state for all CMUs

Before entering suspend, some clocks must be set to some specific
configuration. For example, top-level MUX clocks in each CMU should be
switched to OSCCLK input, etc. This is needed by the firmware to
properly perform system suspend operation. Provide the suspend state for
mentioned clocks using 'suspend_regs' feature.

This patch was inspired by commit a766065279e2 ("clk: samsung:
exynos5433: Add suspend state for TOP, CPIF & PERIC CMUs").

Signed-off-by: Sam Protsenko <[email protected]>
---
drivers/clk/samsung/clk-exynos850.c | 92 +++++++++++++++++++++++++++++
1 file changed, 92 insertions(+)

diff --git a/drivers/clk/samsung/clk-exynos850.c b/drivers/clk/samsung/clk-exynos850.c
index 98b23af7324d..5664d17bae83 100644
--- a/drivers/clk/samsung/clk-exynos850.c
+++ b/drivers/clk/samsung/clk-exynos850.c
@@ -186,6 +186,12 @@ static const unsigned long top_clk_regs[] __initconst = {
CLK_CON_GAT_GATE_CLKCMU_PERI_UART,
};

+static const struct samsung_clk_reg_dump top_suspend_regs[] = {
+ { PLL_CON0_PLL_MMC, 0 },
+ { PLL_CON0_PLL_SHARED0, 0 },
+ { PLL_CON0_PLL_SHARED1, 0 },
+};
+
/*
* Do not provide PLL tables to core PLLs, as MANUAL_PLL_CTRL bit is not set
* for those PLLs by default, so set_rate operation would fail.
@@ -489,6 +495,8 @@ static const struct samsung_cmu_info top_cmu_info __initconst = {
.nr_clk_ids = TOP_NR_CLK,
.clk_regs = top_clk_regs,
.nr_clk_regs = ARRAY_SIZE(top_clk_regs),
+ .suspend_regs = top_suspend_regs,
+ .nr_suspend_regs = ARRAY_SIZE(top_suspend_regs),
};

static void __init exynos850_cmu_top_init(struct device_node *np)
@@ -547,6 +555,13 @@ static const unsigned long apm_clk_regs[] __initconst = {
CLK_CON_GAT_GOUT_APM_SYSREG_APM_PCLK,
};

+static const struct samsung_clk_reg_dump apm_suspend_regs[] = {
+ { PLL_CON0_MUX_CLKCMU_APM_BUS_USER, 0 },
+ { PLL_CON0_MUX_CLK_RCO_APM_I3C_USER, 0 },
+ { PLL_CON0_MUX_CLK_RCO_APM_USER, 0 },
+ { PLL_CON0_MUX_DLL_USER, 0 },
+};
+
/* List of parent clocks for Muxes in CMU_APM */
PNAME(mout_apm_bus_user_p) = { "oscclk_rco_apm", "dout_clkcmu_apm_bus" };
PNAME(mout_rco_apm_i3c_user_p) = { "oscclk_rco_apm", "clk_rco_i3c_pmic" };
@@ -629,6 +644,8 @@ static const struct samsung_cmu_info apm_cmu_info __initconst = {
.nr_clk_ids = APM_NR_CLK,
.clk_regs = apm_clk_regs,
.nr_clk_regs = ARRAY_SIZE(apm_clk_regs),
+ .suspend_regs = apm_suspend_regs,
+ .nr_suspend_regs = ARRAY_SIZE(apm_suspend_regs),
.clk_name = "dout_clkcmu_apm_bus",
};

@@ -746,6 +763,12 @@ static const unsigned long aud_clk_regs[] __initconst = {
CLK_CON_GAT_GOUT_AUD_WDT_PCLK,
};

+static const struct samsung_clk_reg_dump aud_suspend_regs[] = {
+ { PLL_CON0_PLL_AUD, 0 },
+ { PLL_CON0_MUX_CLKCMU_AUD_CPU_USER, 0 },
+ { PLL_CON0_MUX_TICK_USB_USER, 0 },
+};
+
/* List of parent clocks for Muxes in CMU_AUD */
PNAME(mout_aud_pll_p) = { "oscclk", "fout_aud_pll" };
PNAME(mout_aud_cpu_user_p) = { "oscclk", "dout_aud" };
@@ -912,6 +935,8 @@ static const struct samsung_cmu_info aud_cmu_info __initconst = {
.nr_clk_ids = AUD_NR_CLK,
.clk_regs = aud_clk_regs,
.nr_clk_regs = ARRAY_SIZE(aud_clk_regs),
+ .suspend_regs = aud_suspend_regs,
+ .nr_suspend_regs = ARRAY_SIZE(aud_suspend_regs),
.clk_name = "dout_aud",
};

@@ -950,6 +975,12 @@ static const unsigned long cmgp_clk_regs[] __initconst = {
CLK_CON_GAT_GOUT_CMGP_USI_CMGP1_PCLK,
};

+static const struct samsung_clk_reg_dump cmgp_suspend_regs[] = {
+ { CLK_CON_MUX_CLK_CMGP_ADC, 0 },
+ { CLK_CON_MUX_MUX_CLK_CMGP_USI_CMGP0, 0 },
+ { CLK_CON_MUX_MUX_CLK_CMGP_USI_CMGP1, 0 },
+};
+
/* List of parent clocks for Muxes in CMU_CMGP */
PNAME(mout_cmgp_usi0_p) = { "clk_rco_cmgp", "gout_clkcmu_cmgp_bus" };
PNAME(mout_cmgp_usi1_p) = { "clk_rco_cmgp", "gout_clkcmu_cmgp_bus" };
@@ -1015,6 +1046,8 @@ static const struct samsung_cmu_info cmgp_cmu_info __initconst = {
.nr_clk_ids = CMGP_NR_CLK,
.clk_regs = cmgp_clk_regs,
.nr_clk_regs = ARRAY_SIZE(cmgp_clk_regs),
+ .suspend_regs = cmgp_suspend_regs,
+ .nr_suspend_regs = ARRAY_SIZE(cmgp_suspend_regs),
.clk_name = "gout_clkcmu_cmgp_bus",
};

@@ -1051,6 +1084,11 @@ static const unsigned long g3d_clk_regs[] __initconst = {
CLK_CON_GAT_GOUT_G3D_SYSREG_PCLK,
};

+static const struct samsung_clk_reg_dump g3d_suspend_regs[] = {
+ { PLL_CON0_PLL_G3D, 0 },
+ { PLL_CON0_MUX_CLKCMU_G3D_SWITCH_USER, 0 },
+};
+
/* List of parent clocks for Muxes in CMU_G3D */
PNAME(mout_g3d_pll_p) = { "oscclk", "fout_g3d_pll" };
PNAME(mout_g3d_switch_user_p) = { "oscclk", "dout_g3d_switch" };
@@ -1111,6 +1149,8 @@ static const struct samsung_cmu_info g3d_cmu_info __initconst = {
.nr_clk_ids = G3D_NR_CLK,
.clk_regs = g3d_clk_regs,
.nr_clk_regs = ARRAY_SIZE(g3d_clk_regs),
+ .suspend_regs = g3d_suspend_regs,
+ .nr_suspend_regs = ARRAY_SIZE(g3d_suspend_regs),
.clk_name = "dout_g3d_switch",
};

@@ -1153,6 +1193,13 @@ static const unsigned long hsi_clk_regs[] __initconst = {
CLK_CON_GAT_GOUT_HSI_USB20DRD_TOP_BUS_CLK_EARLY,
};

+static const struct samsung_clk_reg_dump hsi_suspend_regs[] = {
+ { PLL_CON0_MUX_CLKCMU_HSI_BUS_USER, 0 },
+ { PLL_CON0_MUX_CLKCMU_HSI_MMC_CARD_USER, 0 },
+ { PLL_CON0_MUX_CLKCMU_HSI_USB20DRD_USER, 0 },
+ { CLK_CON_MUX_MUX_CLK_HSI_RTC, 0 },
+};
+
/* List of parent clocks for Muxes in CMU_HSI */
PNAME(mout_hsi_bus_user_p) = { "oscclk", "dout_hsi_bus" };
PNAME(mout_hsi_mmc_card_user_p) = { "oscclk", "dout_hsi_mmc_card" };
@@ -1213,6 +1260,8 @@ static const struct samsung_cmu_info hsi_cmu_info __initconst = {
.nr_clk_ids = HSI_NR_CLK,
.clk_regs = hsi_clk_regs,
.nr_clk_regs = ARRAY_SIZE(hsi_clk_regs),
+ .suspend_regs = hsi_suspend_regs,
+ .nr_suspend_regs = ARRAY_SIZE(hsi_suspend_regs),
.clk_name = "dout_hsi_bus",
};

@@ -1268,6 +1317,13 @@ static const unsigned long is_clk_regs[] __initconst = {
CLK_CON_GAT_GOUT_IS_SYSREG_PCLK,
};

+static const struct samsung_clk_reg_dump is_suspend_regs[] = {
+ { PLL_CON0_MUX_CLKCMU_IS_BUS_USER, 0 },
+ { PLL_CON0_MUX_CLKCMU_IS_GDC_USER, 0 },
+ { PLL_CON0_MUX_CLKCMU_IS_ITP_USER, 0 },
+ { PLL_CON0_MUX_CLKCMU_IS_VRA_USER, 0 },
+};
+
/* List of parent clocks for Muxes in CMU_IS */
PNAME(mout_is_bus_user_p) = { "oscclk", "dout_is_bus" };
PNAME(mout_is_itp_user_p) = { "oscclk", "dout_is_itp" };
@@ -1345,6 +1401,8 @@ static const struct samsung_cmu_info is_cmu_info __initconst = {
.nr_clk_ids = IS_NR_CLK,
.clk_regs = is_clk_regs,
.nr_clk_regs = ARRAY_SIZE(is_clk_regs),
+ .suspend_regs = is_suspend_regs,
+ .nr_suspend_regs = ARRAY_SIZE(is_suspend_regs),
.clk_name = "dout_is_bus",
};

@@ -1384,6 +1442,13 @@ static const unsigned long mfcmscl_clk_regs[] __initconst = {
CLK_CON_GAT_GOUT_MFCMSCL_SYSREG_PCLK,
};

+static const struct samsung_clk_reg_dump mfcmscl_suspend_regs[] = {
+ { PLL_CON0_MUX_CLKCMU_MFCMSCL_JPEG_USER, 0 },
+ { PLL_CON0_MUX_CLKCMU_MFCMSCL_M2M_USER, 0 },
+ { PLL_CON0_MUX_CLKCMU_MFCMSCL_MCSC_USER, 0 },
+ { PLL_CON0_MUX_CLKCMU_MFCMSCL_MFC_USER, 0 },
+};
+
/* List of parent clocks for Muxes in CMU_MFCMSCL */
PNAME(mout_mfcmscl_mfc_user_p) = { "oscclk", "dout_mfcmscl_mfc" };
PNAME(mout_mfcmscl_m2m_user_p) = { "oscclk", "dout_mfcmscl_m2m" };
@@ -1454,6 +1519,8 @@ static const struct samsung_cmu_info mfcmscl_cmu_info __initconst = {
.nr_clk_ids = MFCMSCL_NR_CLK,
.clk_regs = mfcmscl_clk_regs,
.nr_clk_regs = ARRAY_SIZE(mfcmscl_clk_regs),
+ .suspend_regs = mfcmscl_suspend_regs,
+ .nr_suspend_regs = ARRAY_SIZE(mfcmscl_suspend_regs),
.clk_name = "dout_mfcmscl_mfc",
};

@@ -1532,6 +1599,13 @@ static const unsigned long peri_clk_regs[] __initconst = {
CLK_CON_GAT_GOUT_PERI_WDT_1_PCLK,
};

+static const struct samsung_clk_reg_dump peri_suspend_regs[] = {
+ { PLL_CON0_MUX_CLKCMU_PERI_BUS_USER, 0 },
+ { PLL_CON0_MUX_CLKCMU_PERI_HSI2C_USER, 0 },
+ { PLL_CON0_MUX_CLKCMU_PERI_SPI_USER, 0 },
+ { PLL_CON0_MUX_CLKCMU_PERI_UART_USER, 0 },
+};
+
/* List of parent clocks for Muxes in CMU_PERI */
PNAME(mout_peri_bus_user_p) = { "oscclk", "dout_peri_bus" };
PNAME(mout_peri_uart_user_p) = { "oscclk", "dout_peri_uart" };
@@ -1629,6 +1703,8 @@ static const struct samsung_cmu_info peri_cmu_info __initconst = {
.nr_clk_ids = PERI_NR_CLK,
.clk_regs = peri_clk_regs,
.nr_clk_regs = ARRAY_SIZE(peri_clk_regs),
+ .suspend_regs = peri_suspend_regs,
+ .nr_suspend_regs = ARRAY_SIZE(peri_suspend_regs),
.clk_name = "dout_peri_bus",
};

@@ -1676,6 +1752,14 @@ static const unsigned long core_clk_regs[] __initconst = {
CLK_CON_GAT_GOUT_CORE_SYSREG_CORE_PCLK,
};

+static const struct samsung_clk_reg_dump core_suspend_regs[] = {
+ { PLL_CON0_MUX_CLKCMU_CORE_BUS_USER, 0 },
+ { PLL_CON0_MUX_CLKCMU_CORE_CCI_USER, 0 },
+ { PLL_CON0_MUX_CLKCMU_CORE_MMC_EMBD_USER, 0 },
+ { PLL_CON0_MUX_CLKCMU_CORE_SSS_USER, 0 },
+ { CLK_CON_MUX_MUX_CLK_CORE_GIC, 0x1 },
+};
+
/* List of parent clocks for Muxes in CMU_CORE */
PNAME(mout_core_bus_user_p) = { "oscclk", "dout_core_bus" };
PNAME(mout_core_cci_user_p) = { "oscclk", "dout_core_cci" };
@@ -1736,6 +1820,8 @@ static const struct samsung_cmu_info core_cmu_info __initconst = {
.nr_clk_ids = CORE_NR_CLK,
.clk_regs = core_clk_regs,
.nr_clk_regs = ARRAY_SIZE(core_clk_regs),
+ .suspend_regs = core_suspend_regs,
+ .nr_suspend_regs = ARRAY_SIZE(core_suspend_regs),
.clk_name = "dout_core_bus",
};

@@ -1766,6 +1852,10 @@ static const unsigned long dpu_clk_regs[] __initconst = {
CLK_CON_GAT_GOUT_DPU_SYSREG_PCLK,
};

+static const struct samsung_clk_reg_dump dpu_suspend_regs[] = {
+ { PLL_CON0_MUX_CLKCMU_DPU_USER, 0 },
+};
+
/* List of parent clocks for Muxes in CMU_DPU */
PNAME(mout_dpu_user_p) = { "oscclk", "dout_dpu" };

@@ -1810,6 +1900,8 @@ static const struct samsung_cmu_info dpu_cmu_info __initconst = {
.nr_clk_ids = DPU_NR_CLK,
.clk_regs = dpu_clk_regs,
.nr_clk_regs = ARRAY_SIZE(dpu_clk_regs),
+ .suspend_regs = dpu_suspend_regs,
+ .nr_suspend_regs = ARRAY_SIZE(dpu_suspend_regs),
.clk_name = "dout_dpu",
};

--
2.39.2


2023-03-08 23:39:02

by Sam Protsenko

[permalink] [raw]
Subject: [PATCH 6/7] clk: samsung: exynos850: Enable PM support in clk-exynos850

Some CMUs in Exynos850 SoC belong to power domains. In order to support
"power-domains" property for such CMUs, use
exynos_arm64_register_cmu_pm() API instead of
exynos_arm64_register_cmu() in the probe function, and also provide PM
ops for suspend/resume accordingly.

Signed-off-by: Sam Protsenko <[email protected]>
---
drivers/clk/samsung/clk-exynos850.c | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/clk/samsung/clk-exynos850.c b/drivers/clk/samsung/clk-exynos850.c
index 5664d17bae83..bbf0498dd0b0 100644
--- a/drivers/clk/samsung/clk-exynos850.c
+++ b/drivers/clk/samsung/clk-exynos850.c
@@ -9,8 +9,8 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>

#include <dt-bindings/clock/exynos850.h>

@@ -1909,13 +1909,7 @@ static const struct samsung_cmu_info dpu_cmu_info __initconst = {

static int __init exynos850_cmu_probe(struct platform_device *pdev)
{
- const struct samsung_cmu_info *info;
- struct device *dev = &pdev->dev;
-
- info = of_device_get_match_data(dev);
- exynos_arm64_register_cmu(dev, dev->of_node, info);
-
- return 0;
+ return exynos_arm64_register_cmu_pm(pdev, true);
}

static const struct of_device_id exynos850_cmu_of_match[] = {
@@ -1950,11 +1944,19 @@ static const struct of_device_id exynos850_cmu_of_match[] = {
},
};

+static const struct dev_pm_ops exynos850_cmu_pm_ops = {
+ SET_RUNTIME_PM_OPS(exynos_arm64_cmu_suspend, exynos_arm64_cmu_resume,
+ NULL)
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+};
+
static struct platform_driver exynos850_cmu_driver __refdata = {
.driver = {
.name = "exynos850-cmu",
.of_match_table = exynos850_cmu_of_match,
.suppress_bind_attrs = true,
+ .pm = &exynos850_cmu_pm_ops,
},
.probe = exynos850_cmu_probe,
};
--
2.39.2


2023-03-08 23:39:20

by Sam Protsenko

[permalink] [raw]
Subject: [PATCH 7/7] arm64: dts: exynos: Remove clock from Exynos850 pmu_system_controller

As described in the corresponding binding documentation for
"samsung,exynos850-pmu", the "clocks" property should be used for
specifying CLKOUT mux inputs. Therefore, the clock provided to exynos850
pmu_system_controller is incorrect and should be removed. Instead of
making syscon regmap keep that clock running for PMU accesses, it should
be made always running in the clock driver, because the kernel is not
the only software accessing PMU registers on Exynos850 platform.

Signed-off-by: Sam Protsenko <[email protected]>
---
arch/arm64/boot/dts/exynos/exynos850.dtsi | 1 -
1 file changed, 1 deletion(-)

diff --git a/arch/arm64/boot/dts/exynos/exynos850.dtsi b/arch/arm64/boot/dts/exynos/exynos850.dtsi
index d67e98120313..aa077008b3be 100644
--- a/arch/arm64/boot/dts/exynos/exynos850.dtsi
+++ b/arch/arm64/boot/dts/exynos/exynos850.dtsi
@@ -200,7 +200,6 @@ gic: interrupt-controller@12a01000 {
pmu_system_controller: system-controller@11860000 {
compatible = "samsung,exynos850-pmu", "syscon";
reg = <0x11860000 0x10000>;
- clocks = <&cmu_apm CLK_GOUT_PMU_ALIVE_PCLK>;

reboot: syscon-reboot {
compatible = "syscon-reboot";
--
2.39.2


2023-03-10 14:43:53

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH 1/7] dt-bindings: clock: exynos850: Add power-domains property

On 09/03/2023 00:38, Sam Protsenko wrote:
> Document power-domains property in Exynos850 clock controller.

This we see from the diff. You need to say why, e.g. "several clock
controllers are part of their power domain and require domain to be on
for operation."

>
> Signed-off-by: Sam Protsenko <[email protected]>
> ---
> .../devicetree/bindings/clock/samsung,exynos850-clock.yaml | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/clock/samsung,exynos850-clock.yaml b/Documentation/devicetree/bindings/clock/samsung,exynos850-clock.yaml
> index 8aa87b8c1b33..cc1e9173b272 100644
> --- a/Documentation/devicetree/bindings/clock/samsung,exynos850-clock.yaml
> +++ b/Documentation/devicetree/bindings/clock/samsung,exynos850-clock.yaml
> @@ -54,6 +54,9 @@ properties:
> "#clock-cells":
> const: 1
>
> + power-domains:
> + maxItems: 1
> +
> reg:
> maxItems: 1
>

Best regards,
Krzysztof


2023-03-10 15:15:49

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH 2/7] dt-bindings: clock: exynos850: Add tzpc property

On 09/03/2023 00:38, Sam Protsenko wrote:
> Exynos850 requires extra TZPC handling to keep CMU registers non-secure
> (accessible from the kernel) after PM resume. It's done using a specific
> SMC call to the EL3 monitor.
>
> Describe "samsung,tzpc" property for Exynos850 clock controller which
> allows one to specify the SMC call address for PD capable CMUs.
>
> Signed-off-by: Sam Protsenko <[email protected]>
> ---
> .../bindings/clock/samsung,exynos850-clock.yaml | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/clock/samsung,exynos850-clock.yaml b/Documentation/devicetree/bindings/clock/samsung,exynos850-clock.yaml
> index cc1e9173b272..5098dce5caf6 100644
> --- a/Documentation/devicetree/bindings/clock/samsung,exynos850-clock.yaml
> +++ b/Documentation/devicetree/bindings/clock/samsung,exynos850-clock.yaml
> @@ -60,6 +60,16 @@ properties:
> reg:
> maxItems: 1
>
> + samsung,tzpc:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description:
> + The register address in corresponding Trust Zone Protection Control block
> + for setting the CMU registers access to non-secure. If provided, it'll be
> + used for issuing SMC calls to EL3 monitor during CMU's PM suspend and
> + resume operations, ensuring CMU registers are unprotected after waking up.

Do not store register addresses of MMIO in some fields. If this is part
of clock MMIO, then it could be address space in reg. If it is not, you
cannot store someone's else address space here. If this is someone's
else address space, then you either need syscon or phandle to dedicated
device (something like qcom,scm or other secure monitor channel).

> +
> + This property is optional.

Drop, It's already optional if not required.

Best regards,
Krzysztof


2023-03-13 07:26:40

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH 7/7] arm64: dts: exynos: Remove clock from Exynos850 pmu_system_controller

On 09/03/2023 00:38, Sam Protsenko wrote:
> As described in the corresponding binding documentation for
> "samsung,exynos850-pmu", the "clocks" property should be used for
> specifying CLKOUT mux inputs. Therefore, the clock provided to exynos850
> pmu_system_controller is incorrect and should be removed. Instead of
> making syscon regmap keep that clock running for PMU accesses, it should
> be made always running in the clock driver, because the kernel is not
> the only software accessing PMU registers on Exynos850 platform.
>
> Signed-off-by: Sam Protsenko <[email protected]>
> ---
> arch/arm64/boot/dts/exynos/exynos850.dtsi | 1 -
> 1 file changed, 1 deletion(-)

To avoid any bisectability issues, I will apply this in the next cycle.

Best regards,
Krzysztof


2023-03-13 07:27:36

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: (subset) [PATCH 4/7] clk: samsung: exynos850: Make PMU_ALIVE_PCLK critical

On Wed, 8 Mar 2023 17:38:19 -0600, Sam Protsenko wrote:
> PMU_ALIVE_PCLK is needed for PMU registers access, and it must be always
> running, as not only the kernel accesses PMU registers. Make it critical
> to ensure that.
>
>

Applied, thanks!

[4/7] clk: samsung: exynos850: Make PMU_ALIVE_PCLK critical
https://git.kernel.org/krzk/linux/c/babb3e6a8a8e5a61a65d4463610108808139b23e

Best regards,
--
Krzysztof Kozlowski <[email protected]>

2023-05-13 19:35:13

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: (subset) [PATCH 7/7] arm64: dts: exynos: Remove clock from Exynos850 pmu_system_controller


On Wed, 08 Mar 2023 17:38:22 -0600, Sam Protsenko wrote:
> As described in the corresponding binding documentation for
> "samsung,exynos850-pmu", the "clocks" property should be used for
> specifying CLKOUT mux inputs. Therefore, the clock provided to exynos850
> pmu_system_controller is incorrect and should be removed. Instead of
> making syscon regmap keep that clock running for PMU accesses, it should
> be made always running in the clock driver, because the kernel is not
> the only software accessing PMU registers on Exynos850 platform.
>
> [...]

Applied, thanks!

[7/7] arm64: dts: exynos: Remove clock from Exynos850 pmu_system_controller
https://git.kernel.org/krzk/linux/c/858fd147234dbb66401bc102968a479f92e7ad43

Best regards,
--
Krzysztof Kozlowski <[email protected]>