mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/3] PM: spacemit: Add power domain support
@ 2026-09-18  2:40 Yixun Lan
  2026-09-18  2:40 ` [PATCH 1/3] dt-bindings: power: spacemit: Add power domain controller Yixun Lan
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Yixun Lan @ 2026-09-18  2:40 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
  Cc: devicetree, linux-riscv, spacemit, linux-kernel, linux-pm, Yixun Lan

In this series, we try to add a Power Domain driver support for SpacemiT
K1/K3 SoCs, the driver implement the power-switch functionaly which support
power on/off, and it's based on Linux Generic PM Domain framework and
similiar to vendor K1's implementation, but unlike the K3's vendor
version which is more complicated.

Signed-off-by: Yixun Lan <dlan@kernel.org>
---
Yixun Lan (3):
      dt-bindings: power: spacemit: Add power domain controller
      pmdomain: spacemit: Add power domain driver
      dts: riscv: spacemit: Add power domain nodes

 .../bindings/power/spacemit,power-controller.yaml  |  43 ++
 arch/riscv/boot/dts/spacemit/k1.dtsi               |   6 +
 arch/riscv/boot/dts/spacemit/k3.dtsi               |   6 +
 drivers/pmdomain/Kconfig                           |   1 +
 drivers/pmdomain/Makefile                          |   1 +
 drivers/pmdomain/spacemit/Kconfig                  |  15 +
 drivers/pmdomain/spacemit/Makefile                 |   1 +
 drivers/pmdomain/spacemit/pm_domains.c             | 448 +++++++++++++++++++++
 include/dt-bindings/power/spacemit,k1-power.h      |  14 +
 include/dt-bindings/power/spacemit,k3-power.h      |  12 +
 10 files changed, 547 insertions(+)
---
base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
change-id: 20260909-04-k3-pm-support-0bef40e87fd7

Best regards,
--  
Yixun Lan <dlan@kernel.org>


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/3] dt-bindings: power: spacemit: Add power domain controller
  2026-09-18  2:40 [PATCH 0/3] PM: spacemit: Add power domain support Yixun Lan
@ 2026-09-18  2:40 ` Yixun Lan
  2026-09-18  2:40 ` [PATCH 2/3] pmdomain: spacemit: Add power domain driver Yixun Lan
  2026-09-18  2:40 ` [PATCH 3/3] dts: riscv: spacemit: Add power domain nodes Yixun Lan
  2 siblings, 0 replies; 8+ messages in thread
From: Yixun Lan @ 2026-09-18  2:40 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
  Cc: devicetree, linux-riscv, spacemit, linux-kernel, linux-pm, Yixun Lan

Add initial power domain driver support for SpacemiT K1/K3 SoC, The Power
Domain Controller is SoC internal module which is part of APMU (Advanced
Power Management Unit), it is responsible for managing power across multi
power domains, which includes power on/off, isolation, power-on sequence.

Signed-off-by: Yixun Lan <dlan@kernel.org>
---
 .../bindings/power/spacemit,power-controller.yaml  | 43 ++++++++++++++++++++++
 include/dt-bindings/power/spacemit,k1-power.h      | 14 +++++++
 include/dt-bindings/power/spacemit,k3-power.h      | 12 ++++++
 3 files changed, 69 insertions(+)

diff --git a/Documentation/devicetree/bindings/power/spacemit,power-controller.yaml b/Documentation/devicetree/bindings/power/spacemit,power-controller.yaml
new file mode 100644
index 000000000000..f869285f84da
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/spacemit,power-controller.yaml
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/spacemit,power-controller.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SpacemiT Power Domains Controller
+
+maintainers:
+  - Yixun Lan <dlan@kernel.org>
+
+description: |
+  SpacemiT processors include support for multiple power domains which can be
+  powered on/off by software based on different application scenes to save power.
+
+properties:
+  compatible:
+    enum:
+      - spacemit,k1-power-controller
+      - spacemit,k3-power-controller
+
+  '#power-domain-cells':
+    const: 1
+
+  spacemit,apmu:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      A phandle to APMU syscon to control registers for power domain
+
+required:
+  - compatible
+  - '#power-domain-cells'
+  - spacemit,apmu
+
+additionalProperties: false
+
+examples:
+  - |
+    power-controller {
+            compatible = "spacemit,k1-power-controller";
+            spacemit,apmu = <&syscon_apmu>;
+            #power-domain-cells = <1>;
+    };
diff --git a/include/dt-bindings/power/spacemit,k1-power.h b/include/dt-bindings/power/spacemit,k1-power.h
new file mode 100644
index 000000000000..41ef540b5c44
--- /dev/null
+++ b/include/dt-bindings/power/spacemit,k1-power.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+
+#ifndef _DT_BINDINGS_SPACEMIT_K1_POWER_H_
+#define _DT_BINDINGS_SPACEMIT_K1_POWER_H_
+
+#define K1_PMDOMAIN_VPU		0
+#define K1_PMDOMAIN_GPU		1
+#define K1_PMDOMAIN_LCD		2
+#define K1_PMDOMAIN_ISP		3
+#define K1_PMDOMAIN_AUDIO	4
+#define K1_PMDOMAIN_GNSS	5
+#define K1_PMDOMAIN_HDMI	6
+
+#endif
diff --git a/include/dt-bindings/power/spacemit,k3-power.h b/include/dt-bindings/power/spacemit,k3-power.h
new file mode 100644
index 000000000000..54b39f2f0936
--- /dev/null
+++ b/include/dt-bindings/power/spacemit,k3-power.h
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+
+#ifndef _DT_BINDINGS_SPACEMIT_K3_POWER_H_
+#define _DT_BINDINGS_SPACEMIT_K3_POWER_H_
+
+#define K3_PMDOMAIN_VPU		0
+#define K3_PMDOMAIN_GPU		1
+#define K3_PMDOMAIN_AUDIO	2
+#define K3_PMDOMAIN_LCD0	3
+#define K3_PMDOMAIN_LCD1	4
+
+#endif

-- 
2.55.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 2/3] pmdomain: spacemit: Add power domain driver
  2026-09-18  2:40 [PATCH 0/3] PM: spacemit: Add power domain support Yixun Lan
  2026-09-18  2:40 ` [PATCH 1/3] dt-bindings: power: spacemit: Add power domain controller Yixun Lan
@ 2026-09-18  2:40 ` Yixun Lan
  2026-09-18  9:00   ` Icenowy Zheng
  2026-09-18  2:40 ` [PATCH 3/3] dts: riscv: spacemit: Add power domain nodes Yixun Lan
  2 siblings, 1 reply; 8+ messages in thread
From: Yixun Lan @ 2026-09-18  2:40 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
  Cc: devicetree, linux-riscv, spacemit, linux-kernel, linux-pm, Yixun Lan

  SpacemiT's PMU (Power Management Unit) consist of several power domains
which can be managed independently, depending on different application
scenario, each domain can be powered on/off for saving power.

  The driver is implemented based on Linux Generic PM Domain framework.
From a hardware perspective, either of two distinct power-on sequences
are supported, in software mode (SW mode), the driver is responsible for
controlling the states of bits such as sleep1, sleep2, isolation and
pwr_state, while in hardware mode (HW mode), the PMU hardware will complete
the sequence automatically without requiring software intervention.

Signed-off-by: Yixun Lan <dlan@kernel.org>
---
 drivers/pmdomain/Kconfig               |   1 +
 drivers/pmdomain/Makefile              |   1 +
 drivers/pmdomain/spacemit/Kconfig      |  15 ++
 drivers/pmdomain/spacemit/Makefile     |   1 +
 drivers/pmdomain/spacemit/pm_domains.c | 448 +++++++++++++++++++++++++++++++++
 5 files changed, 466 insertions(+)

diff --git a/drivers/pmdomain/Kconfig b/drivers/pmdomain/Kconfig
index 23076ae90e66..0610acd030f6 100644
--- a/drivers/pmdomain/Kconfig
+++ b/drivers/pmdomain/Kconfig
@@ -13,6 +13,7 @@ source "drivers/pmdomain/qcom/Kconfig"
 source "drivers/pmdomain/renesas/Kconfig"
 source "drivers/pmdomain/rockchip/Kconfig"
 source "drivers/pmdomain/samsung/Kconfig"
+source "drivers/pmdomain/spacemit/Kconfig"
 source "drivers/pmdomain/st/Kconfig"
 source "drivers/pmdomain/starfive/Kconfig"
 source "drivers/pmdomain/sunxi/Kconfig"
diff --git a/drivers/pmdomain/Makefile b/drivers/pmdomain/Makefile
index ebc802f13eb9..ba25b444e263 100644
--- a/drivers/pmdomain/Makefile
+++ b/drivers/pmdomain/Makefile
@@ -11,6 +11,7 @@ obj-y					+= qcom/
 obj-y					+= renesas/
 obj-y					+= rockchip/
 obj-y					+= samsung/
+obj-y					+= spacemit/
 obj-y					+= st/
 obj-y					+= starfive/
 obj-y					+= sunxi/
diff --git a/drivers/pmdomain/spacemit/Kconfig b/drivers/pmdomain/spacemit/Kconfig
new file mode 100644
index 000000000000..4b927beedc7c
--- /dev/null
+++ b/drivers/pmdomain/spacemit/Kconfig
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+menu "SpacemiT PM Domains"
+
+config SPACEMIT_PM_DOMAINS
+	bool "PM Domain driver for SpacemiT SoC"
+	depends on PM
+	depends on OF
+	depends on MFD_SYSCON
+	select PM_GENERIC_DOMAINS
+	help
+	  PM Domain driver for SpacemiT SoC. Say Y if you want to support
+	  SpacemiT SoCs.
+
+endmenu
diff --git a/drivers/pmdomain/spacemit/Makefile b/drivers/pmdomain/spacemit/Makefile
new file mode 100644
index 000000000000..5e8a740ba494
--- /dev/null
+++ b/drivers/pmdomain/spacemit/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SPACEMIT_PM_DOMAINS)	+= pm_domains.o
diff --git a/drivers/pmdomain/spacemit/pm_domains.c b/drivers/pmdomain/spacemit/pm_domains.c
new file mode 100644
index 000000000000..d563e4e4e232
--- /dev/null
+++ b/drivers/pmdomain/spacemit/pm_domains.c
@@ -0,0 +1,448 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Spacemit Generic power domain support.
+ *
+ * Copyright (c) 2026 SpacemiT Technology Co. Ltd
+ */
+
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <dt-bindings/power/spacemit,k1-power.h>
+#include <dt-bindings/power/spacemit,k3-power.h>
+
+#define APMU_POWER_STATUS_REG	0xf0
+#define APMU_POWER_TIMEOUT_US	10000
+
+struct spacemit_pm_domain_param {
+	int reg_pwr_ctrl;
+	int bit_hw_mode;
+	int bit_sleep2;
+	int bit_sleep1;
+	int bit_isolation;
+	int bit_auto_pwr_on;
+	int bit_hw_pwr_stat;
+	int bit_pwr_stat;
+	int use_hw;
+	const char *name;
+};
+
+struct spacemit_pm_domain {
+	struct generic_pm_domain genpd;
+	int pm_index;
+	const struct spacemit_pm_domain_param *param;
+};
+
+struct spacemit_pmu {
+	struct device *dev;
+	struct genpd_onecell_data genpd_data;
+	struct regmap *regmap;
+	struct spacemit_pm_domain **domains;
+	int num_domains;
+};
+
+struct spacemit_pm_of_data {
+	int num_domains;
+	const struct spacemit_pm_domain_param *param;
+};
+
+static struct spacemit_pmu *gpmu;
+
+static int spacemit_pd_power_off(struct generic_pm_domain *domain)
+{
+	struct spacemit_pm_domain *spd = container_of(domain, struct spacemit_pm_domain, genpd);
+	const struct spacemit_pm_domain_param *p = spd->param;
+	unsigned int val;
+	int ret;
+
+	if (!spd->param->use_hw) {
+		regmap_clear_bits(gpmu->regmap, p->reg_pwr_ctrl, BIT(p->bit_isolation));
+		fsleep(15);
+
+		val = BIT(p->bit_sleep1) | BIT(p->bit_sleep2);
+		regmap_clear_bits(gpmu->regmap, p->reg_pwr_ctrl, val);
+		fsleep(15);
+
+		ret = regmap_read_poll_timeout(gpmu->regmap,
+					       APMU_POWER_STATUS_REG,
+					       val,
+					       !(val & BIT(p->bit_pwr_stat)),
+					       5,
+					       APMU_POWER_TIMEOUT_US);
+	} else {
+		val = BIT(p->bit_auto_pwr_on) | BIT(p->bit_hw_mode);
+		regmap_clear_bits(gpmu->regmap, p->reg_pwr_ctrl, val);
+		fsleep(15);
+
+		ret = regmap_read_poll_timeout(gpmu->regmap,
+					       APMU_POWER_STATUS_REG,
+					       val,
+					       !(val & BIT(p->bit_hw_pwr_stat)),
+					       5,
+					       APMU_POWER_TIMEOUT_US);
+	}
+
+	if (ret) {
+		dev_err(&domain->dev, "Fail to power-off domain: %d\n",
+				spd->pm_index);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int spacemit_pd_power_on(struct generic_pm_domain *domain)
+{
+	struct spacemit_pm_domain *spd = container_of(domain, struct spacemit_pm_domain, genpd);
+	const struct spacemit_pm_domain_param *p = spd->param;
+	unsigned int val;
+	int ret = 0;
+
+	regmap_read(gpmu->regmap, APMU_POWER_STATUS_REG, &val);
+
+	if (!p->use_hw && (val & BIT(p->bit_pwr_stat))) {
+		val = BIT(p->bit_isolation);
+		regmap_clear_bits(gpmu->regmap, p->reg_pwr_ctrl, val);
+		fsleep(15);
+
+		val = BIT(p->bit_sleep1) | BIT(p->bit_sleep2);
+		regmap_clear_bits(gpmu->regmap, p->reg_pwr_ctrl, val);
+		fsleep(15);
+
+		ret = regmap_read_poll_timeout(gpmu->regmap,
+					       APMU_POWER_STATUS_REG,
+					       val,
+					       !(val & BIT(p->bit_pwr_stat)),
+					       5,
+					       APMU_POWER_TIMEOUT_US);
+	}
+
+	if (p->use_hw && (val & BIT(p->bit_hw_pwr_stat))) {
+		val = BIT(p->bit_auto_pwr_on) | BIT(p->bit_hw_mode);
+		regmap_clear_bits(gpmu->regmap, p->reg_pwr_ctrl, val);
+		fsleep(30);
+
+		ret = regmap_read_poll_timeout(gpmu->regmap,
+					       APMU_POWER_STATUS_REG,
+					       val,
+					       !(val & BIT(p->bit_hw_pwr_stat)),
+					       5,
+					       APMU_POWER_TIMEOUT_US);
+	}
+
+	if (ret < 0) {
+		dev_err(&domain->dev, "power-off domain: %d, error\n", spd->pm_index);
+		return -EBUSY;
+	}
+
+	if (!p->use_hw) {
+		regmap_set_bits(gpmu->regmap, p->reg_pwr_ctrl, BIT(p->bit_sleep1));
+		fsleep(20);
+
+		val = BIT(p->bit_sleep2) | BIT(p->bit_sleep1);
+		regmap_set_bits(gpmu->regmap, p->reg_pwr_ctrl, val);
+		fsleep(20);
+
+		regmap_set_bits(gpmu->regmap, p->reg_pwr_ctrl, BIT(p->bit_isolation));
+		fsleep(15);
+
+		ret = regmap_read_poll_timeout(gpmu->regmap,
+					       APMU_POWER_STATUS_REG,
+					       val,
+					       (val & BIT(p->bit_pwr_stat)),
+					       5,
+					       APMU_POWER_TIMEOUT_US);
+	} else {
+		val = BIT(p->bit_auto_pwr_on) | BIT(p->bit_hw_mode);
+		regmap_set_bits(gpmu->regmap, p->reg_pwr_ctrl, val);
+		fsleep(300);
+
+		ret = regmap_read_poll_timeout(gpmu->regmap,
+					       APMU_POWER_STATUS_REG,
+					       val,
+					       (val & BIT(p->bit_hw_pwr_stat)),
+					       5,
+					       APMU_POWER_TIMEOUT_US);
+	}
+
+	if (ret < 0) {
+		dev_err(&domain->dev, "power-on domain: %d, error\n", spd->pm_index);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static bool spacemit_pm_get_state(struct spacemit_pmu *pmu,
+				  struct spacemit_pm_domain *pd)
+{
+	const struct spacemit_pm_domain_param *p = pd->param;
+	u32 reg, bit;
+
+	regmap_read(pmu->regmap, APMU_POWER_STATUS_REG, &reg);
+
+	bit = p->use_hw ? BIT(pd->param->bit_hw_pwr_stat) :
+		BIT(pd->param->bit_pwr_stat);
+
+	return !!(reg & bit);
+}
+
+static int spacemit_pm_add_one_domain(struct spacemit_pmu *pmu, int id,
+				      const struct spacemit_pm_domain_param *param)
+{
+	struct spacemit_pm_domain *pd;
+
+	pd = devm_kzalloc(pmu->dev, sizeof(*pd), GFP_KERNEL);
+	if (!pd)
+		return -ENOMEM;
+
+	pd->pm_index        = id;
+	pd->param           = param;
+	pd->genpd.name      = param->name;
+	pd->genpd.power_off = spacemit_pd_power_off;
+	pd->genpd.power_on  = spacemit_pd_power_on;
+
+	pm_genpd_init(&pd->genpd, NULL, !spacemit_pm_get_state(pmu, pd));
+
+	pmu->domains[id] = pd;
+
+	return 0;
+}
+
+static void spacemit_pm_domain_cleanup(struct spacemit_pmu *pmu)
+{
+	int i;
+
+	for (i = 0; i < pmu->num_domains; i++) {
+		if (pmu->domains[i])
+			pm_genpd_remove(&pmu->domains[i]->genpd);
+	}
+}
+
+static int spacemit_pm_domain_probe(struct platform_device *pdev)
+{
+	const struct spacemit_pm_of_data *data;
+	struct device *dev = &pdev->dev;
+	struct spacemit_pmu *pmu;
+	int err, i;
+
+	data = device_get_match_data(dev);
+
+	pmu = devm_kzalloc(dev, sizeof(*pmu), GFP_KERNEL);
+	if (!pmu)
+		return -ENOMEM;
+
+	pmu->dev = dev;
+	pmu->num_domains = data->num_domains;
+
+	pmu->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "spacemit,apmu");
+	if (IS_ERR(pmu->regmap))
+		return dev_err_probe(dev, PTR_ERR(pmu->regmap), "failed to get apmu regmap\n");
+
+	pmu->domains = devm_kcalloc(dev, data->num_domains,
+				    sizeof(*pmu->domains), GFP_KERNEL);
+	if (!pmu->domains)
+		return -ENOMEM;
+
+	for (i = 0; i < data->num_domains; i++) {
+		err = spacemit_pm_add_one_domain(pmu, i, &data->param[i]);
+		if (err) {
+			dev_err(dev, "failed to add domain %d: %d\n", i, err);
+			goto err_out;
+		}
+	}
+
+	pmu->genpd_data.domains     = (struct generic_pm_domain **)pmu->domains;
+	pmu->genpd_data.num_domains = data->num_domains;
+
+	err = of_genpd_add_provider_onecell(dev->of_node, &pmu->genpd_data);
+	if (err) {
+		dev_err(dev, "failed to add provider: %d\n", err);
+		goto err_out;
+	}
+
+	gpmu = pmu;
+
+	return 0;
+
+err_out:
+	spacemit_pm_domain_cleanup(pmu);
+	return err;
+}
+
+static const struct spacemit_pm_domain_param k1_domain_params[] = {
+	[K1_PMDOMAIN_VPU] = {
+		.reg_pwr_ctrl		= 0xa8,
+		.bit_sleep2		= 3,
+		.bit_sleep1		= 2,
+		.bit_isolation		= 1,
+		.bit_pwr_stat		= 1,
+		.bit_hw_pwr_stat	= 9,
+		.name			= "vpu",
+	},
+	[K1_PMDOMAIN_GPU] = {
+		.reg_pwr_ctrl		= 0xd0,
+		.bit_sleep2		= 3,
+		.bit_sleep1		= 2,
+		.bit_isolation		= 1,
+		.bit_pwr_stat		= 0,
+		.name			= "gpu",
+	},
+	[K1_PMDOMAIN_LCD] = {
+		.reg_pwr_ctrl		= 0x380,
+		.bit_hw_mode		= 4,
+		.bit_sleep2		= 3,
+		.bit_sleep1		= 2,
+		.bit_isolation		= 1,
+		.bit_auto_pwr_on	= 0,
+		.bit_pwr_stat		= 4,
+		.bit_hw_pwr_stat	= 12,
+		.use_hw			= 1,
+		.name			= "lcd",
+	},
+	[K1_PMDOMAIN_ISP] = {
+		.reg_pwr_ctrl		= 0x37c,
+		.bit_hw_mode		= 4,
+		.bit_sleep2		= 3,
+		.bit_sleep1		= 2,
+		.bit_isolation		= 1,
+		.bit_auto_pwr_on	= 0,
+		.bit_pwr_stat		= 2,
+		.bit_hw_pwr_stat	= 10,
+		.name			= "isp",
+	},
+	[K1_PMDOMAIN_AUDIO] = {
+		.reg_pwr_ctrl		= 0x378,
+		.bit_hw_mode		= 4,
+		.bit_sleep2		= 3,
+		.bit_sleep1		= 2,
+		.bit_isolation		= 1,
+		.bit_auto_pwr_on	= 0,
+		.bit_pwr_stat		= 3,
+		.bit_hw_pwr_stat	= 11,
+		.use_hw			= 1,
+		.name			= "audio",
+	},
+	[K1_PMDOMAIN_GNSS] = {
+		.reg_pwr_ctrl		= 0x13c,
+		.bit_hw_mode		= 4,
+		.bit_sleep2		= 3,
+		.bit_sleep1		= 2,
+		.bit_isolation		= 1,
+		.bit_auto_pwr_on	= 0,
+		.bit_pwr_stat		= 6,
+		.bit_hw_pwr_stat	= 14,
+		.name			= "gnss",
+	},
+	[K1_PMDOMAIN_HDMI] = {
+		.reg_pwr_ctrl		= 0x3f4,
+		.bit_hw_mode		= 4,
+		.bit_sleep2		= 3,
+		.bit_sleep1		= 2,
+		.bit_isolation		= 1,
+		.bit_auto_pwr_on	= 0,
+		.bit_pwr_stat		= 7,
+		.bit_hw_pwr_stat	= 15,
+		.use_hw			= 1,
+		.name			= "hdmi",
+	},
+};
+
+static const struct spacemit_pm_domain_param k3_domain_params[] = {
+	[K3_PMDOMAIN_VPU] = {
+		.bit_auto_pwr_on	= 0,
+		.bit_isolation		= 1,
+		.bit_sleep1		= 2,
+		.bit_sleep2		= 3,
+		.bit_hw_mode		= 4,
+		.bit_pwr_stat		= 2,
+		.bit_hw_pwr_stat	= 9,
+		.use_hw			= 1,
+		.reg_pwr_ctrl		= 0xa8,
+		.name			= "vpu",
+	},
+	[K3_PMDOMAIN_GPU] = {
+		.bit_auto_pwr_on	= 0,
+		.bit_isolation		= 1,
+		.bit_sleep1		= 2,
+		.bit_sleep2		= 3,
+		.bit_hw_mode		= 4,
+		.bit_pwr_stat		= 0,
+		.bit_hw_pwr_stat	= 8,
+		.use_hw			= 1,
+		.reg_pwr_ctrl		= 0xd0,
+		.name			= "gpu",
+	},
+	[K3_PMDOMAIN_AUDIO] = {
+		.bit_auto_pwr_on	= 0,
+		.bit_isolation		= 1,
+		.bit_sleep1		= 2,
+		.bit_sleep2		= 3,
+		.bit_hw_mode		= 4,
+		.bit_pwr_stat		= 3,
+		.reg_pwr_ctrl		= 0x378,
+		.name			= "audio",
+	},
+	[K3_PMDOMAIN_LCD0] = {
+		.bit_auto_pwr_on	= 0,
+		.bit_isolation		= 1,
+		.bit_sleep1		= 2,
+		.bit_sleep2		= 3,
+		.bit_hw_mode		= 4,
+		.bit_pwr_stat		= 4,
+		.bit_hw_pwr_stat	= 12,
+		.use_hw			= 1,
+		.reg_pwr_ctrl		= 0x380,
+		.name			= "lcd0",
+	},
+	[K3_PMDOMAIN_LCD1] = {
+		.bit_auto_pwr_on	= 0,
+		.bit_isolation		= 1,
+		.bit_sleep1		= 2,
+		.bit_sleep2		= 3,
+		.bit_hw_mode		= 4,
+		.bit_pwr_stat		= 5,
+		.bit_hw_pwr_stat	= 15,
+		.use_hw			= 1,
+		.reg_pwr_ctrl		= 0x3f4,
+		.name			= "lcd1",
+	},
+};
+
+static const struct spacemit_pm_of_data k1_of_data = {
+	.num_domains	= ARRAY_SIZE(k1_domain_params),
+	.param		= k1_domain_params,
+};
+
+static const struct spacemit_pm_of_data k3_of_data = {
+	.num_domains	= ARRAY_SIZE(k3_domain_params),
+	.param		= k3_domain_params,
+};
+
+static const struct of_device_id spacemit_pm_domain_dt_match[] = {
+	{
+		.compatible = "spacemit,k1-power-controller",
+		.data = &k1_of_data,
+	},
+	{
+		.compatible = "spacemit,k3-power-controller",
+		.data = &k3_of_data,
+	},
+	{ /* sentinel */ }
+};
+
+static struct platform_driver spacemit_pm_domain_driver = {
+	.probe = spacemit_pm_domain_probe,
+	.driver = {
+		.name           = "spacemit-pm-domain",
+		.of_match_table = spacemit_pm_domain_dt_match,
+	},
+};
+
+builtin_platform_driver(spacemit_pm_domain_driver);
+MODULE_DESCRIPTION("SpacemiT Generic Power Domains driver");
+MODULE_LICENSE("GPL");

-- 
2.55.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 3/3] dts: riscv: spacemit: Add power domain nodes
  2026-09-18  2:40 [PATCH 0/3] PM: spacemit: Add power domain support Yixun Lan
  2026-09-18  2:40 ` [PATCH 1/3] dt-bindings: power: spacemit: Add power domain controller Yixun Lan
  2026-09-18  2:40 ` [PATCH 2/3] pmdomain: spacemit: Add power domain driver Yixun Lan
@ 2026-09-18  2:40 ` Yixun Lan
  2 siblings, 0 replies; 8+ messages in thread
From: Yixun Lan @ 2026-09-18  2:40 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
  Cc: devicetree, linux-riscv, spacemit, linux-kernel, linux-pm, Yixun Lan

Populate the power domain device tree nodes for K1/K3 SoC.

Signed-off-by: Yixun Lan <dlan@kernel.org>
---
 arch/riscv/boot/dts/spacemit/k1.dtsi | 6 ++++++
 arch/riscv/boot/dts/spacemit/k3.dtsi | 6 ++++++
 2 files changed, 12 insertions(+)

diff --git a/arch/riscv/boot/dts/spacemit/k1.dtsi b/arch/riscv/boot/dts/spacemit/k1.dtsi
index 3fabfd34114b..871c913e6fb4 100644
--- a/arch/riscv/boot/dts/spacemit/k1.dtsi
+++ b/arch/riscv/boot/dts/spacemit/k1.dtsi
@@ -1352,4 +1352,10 @@ emmc: mmc@d4281000 {
 			};
 		};
 	};
+
+	pwrc: power-controller {
+		compatible = "spacemit,k1-power-controller";
+		spacemit,apmu = <&syscon_apmu>;
+		#power-domain-cells = <1>;
+	};
 };
diff --git a/arch/riscv/boot/dts/spacemit/k3.dtsi b/arch/riscv/boot/dts/spacemit/k3.dtsi
index c3f2dce0969c..1bf25a657762 100644
--- a/arch/riscv/boot/dts/spacemit/k3.dtsi
+++ b/arch/riscv/boot/dts/spacemit/k3.dtsi
@@ -1306,4 +1306,10 @@ maplic: interrupt-controller@f1800000 {
 			status = "reserved";
 		};
 	};
+
+	pwrc: power-controller {
+		compatible = "spacemit,k3-power-controller";
+		spacemit,apmu = <&syscon_apmu>;
+		#power-domain-cells = <1>;
+	};
 };

-- 
2.55.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/3] pmdomain: spacemit: Add power domain driver
  2026-09-18  2:40 ` [PATCH 2/3] pmdomain: spacemit: Add power domain driver Yixun Lan
@ 2026-09-18  9:00   ` Icenowy Zheng
  2026-09-18 23:01     ` Yixun Lan
  0 siblings, 1 reply; 8+ messages in thread
From: Icenowy Zheng @ 2026-09-18  9:00 UTC (permalink / raw)
  To: Yixun Lan, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Ulf Hansson, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti
  Cc: devicetree, linux-riscv, spacemit, linux-kernel, linux-pm

在 2026-09-18五的 02:40 +0000,Yixun Lan写道:
>   SpacemiT's PMU (Power Management Unit) consist of several power
> domains
> which can be managed independently, depending on different
> application
> scenario, each domain can be powered on/off for saving power.
> 
>   The driver is implemented based on Linux Generic PM Domain
> framework.
> From a hardware perspective, either of two distinct power-on
> sequences
> are supported, in software mode (SW mode), the driver is responsible
> for
> controlling the states of bits such as sleep1, sleep2, isolation and
> pwr_state, while in hardware mode (HW mode), the PMU hardware will
> complete
> the sequence automatically without requiring software intervention.

I think there also exists solutions for K3 that uses RPMI power
domains, and let their ESOS firmware to access the hardware.

What's the relationship of this implementation with the ESOS
implementation? Should the ESOS part be disabled to use this
implementation?

Thanks,
Icenowy

> 
> Signed-off-by: Yixun Lan <dlan@kernel.org>
> ---
>  drivers/pmdomain/Kconfig               |   1 +
>  drivers/pmdomain/Makefile              |   1 +
>  drivers/pmdomain/spacemit/Kconfig      |  15 ++
>  drivers/pmdomain/spacemit/Makefile     |   1 +
>  drivers/pmdomain/spacemit/pm_domains.c | 448
> +++++++++++++++++++++++++++++++++
>  5 files changed, 466 insertions(+)
> 
> diff --git a/drivers/pmdomain/Kconfig b/drivers/pmdomain/Kconfig
> index 23076ae90e66..0610acd030f6 100644
> --- a/drivers/pmdomain/Kconfig
> +++ b/drivers/pmdomain/Kconfig
> @@ -13,6 +13,7 @@ source "drivers/pmdomain/qcom/Kconfig"
>  source "drivers/pmdomain/renesas/Kconfig"
>  source "drivers/pmdomain/rockchip/Kconfig"
>  source "drivers/pmdomain/samsung/Kconfig"
> +source "drivers/pmdomain/spacemit/Kconfig"
>  source "drivers/pmdomain/st/Kconfig"
>  source "drivers/pmdomain/starfive/Kconfig"
>  source "drivers/pmdomain/sunxi/Kconfig"
> diff --git a/drivers/pmdomain/Makefile b/drivers/pmdomain/Makefile
> index ebc802f13eb9..ba25b444e263 100644
> --- a/drivers/pmdomain/Makefile
> +++ b/drivers/pmdomain/Makefile
> @@ -11,6 +11,7 @@ obj-y					+= qcom/
>  obj-y					+= renesas/
>  obj-y					+= rockchip/
>  obj-y					+= samsung/
> +obj-y					+= spacemit/
>  obj-y					+= st/
>  obj-y					+= starfive/
>  obj-y					+= sunxi/
> diff --git a/drivers/pmdomain/spacemit/Kconfig
> b/drivers/pmdomain/spacemit/Kconfig
> new file mode 100644
> index 000000000000..4b927beedc7c
> --- /dev/null
> +++ b/drivers/pmdomain/spacemit/Kconfig
> @@ -0,0 +1,15 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +
> +menu "SpacemiT PM Domains"
> +
> +config SPACEMIT_PM_DOMAINS
> +	bool "PM Domain driver for SpacemiT SoC"
> +	depends on PM
> +	depends on OF
> +	depends on MFD_SYSCON
> +	select PM_GENERIC_DOMAINS
> +	help
> +	  PM Domain driver for SpacemiT SoC. Say Y if you want to
> support
> +	  SpacemiT SoCs.
> +
> +endmenu
> diff --git a/drivers/pmdomain/spacemit/Makefile
> b/drivers/pmdomain/spacemit/Makefile
> new file mode 100644
> index 000000000000..5e8a740ba494
> --- /dev/null
> +++ b/drivers/pmdomain/spacemit/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_SPACEMIT_PM_DOMAINS)	+= pm_domains.o
> diff --git a/drivers/pmdomain/spacemit/pm_domains.c
> b/drivers/pmdomain/spacemit/pm_domains.c
> new file mode 100644
> index 000000000000..d563e4e4e232
> --- /dev/null
> +++ b/drivers/pmdomain/spacemit/pm_domains.c
> @@ -0,0 +1,448 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Spacemit Generic power domain support.
> + *
> + * Copyright (c) 2026 SpacemiT Technology Co. Ltd
> + */
> +
> +#include <linux/io.h>
> +#include <linux/err.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_domain.h>
> +#include <linux/of_platform.h>
> +#include <linux/regmap.h>
> +#include <linux/mfd/syscon.h>
> +#include <dt-bindings/power/spacemit,k1-power.h>
> +#include <dt-bindings/power/spacemit,k3-power.h>
> +
> +#define APMU_POWER_STATUS_REG	0xf0
> +#define APMU_POWER_TIMEOUT_US	10000
> +
> +struct spacemit_pm_domain_param {
> +	int reg_pwr_ctrl;
> +	int bit_hw_mode;
> +	int bit_sleep2;
> +	int bit_sleep1;
> +	int bit_isolation;
> +	int bit_auto_pwr_on;
> +	int bit_hw_pwr_stat;
> +	int bit_pwr_stat;
> +	int use_hw;
> +	const char *name;
> +};
> +
> +struct spacemit_pm_domain {
> +	struct generic_pm_domain genpd;
> +	int pm_index;
> +	const struct spacemit_pm_domain_param *param;
> +};
> +
> +struct spacemit_pmu {
> +	struct device *dev;
> +	struct genpd_onecell_data genpd_data;
> +	struct regmap *regmap;
> +	struct spacemit_pm_domain **domains;
> +	int num_domains;
> +};
> +
> +struct spacemit_pm_of_data {
> +	int num_domains;
> +	const struct spacemit_pm_domain_param *param;
> +};
> +
> +static struct spacemit_pmu *gpmu;
> +
> +static int spacemit_pd_power_off(struct generic_pm_domain *domain)
> +{
> +	struct spacemit_pm_domain *spd = container_of(domain, struct
> spacemit_pm_domain, genpd);
> +	const struct spacemit_pm_domain_param *p = spd->param;
> +	unsigned int val;
> +	int ret;
> +
> +	if (!spd->param->use_hw) {
> +		regmap_clear_bits(gpmu->regmap, p->reg_pwr_ctrl,
> BIT(p->bit_isolation));
> +		fsleep(15);
> +
> +		val = BIT(p->bit_sleep1) | BIT(p->bit_sleep2);
> +		regmap_clear_bits(gpmu->regmap, p->reg_pwr_ctrl,
> val);
> +		fsleep(15);
> +
> +		ret = regmap_read_poll_timeout(gpmu->regmap,
> +					      
> APMU_POWER_STATUS_REG,
> +					       val,
> +					       !(val & BIT(p-
> >bit_pwr_stat)),
> +					       5,
> +					      
> APMU_POWER_TIMEOUT_US);
> +	} else {
> +		val = BIT(p->bit_auto_pwr_on) | BIT(p->bit_hw_mode);
> +		regmap_clear_bits(gpmu->regmap, p->reg_pwr_ctrl,
> val);
> +		fsleep(15);
> +
> +		ret = regmap_read_poll_timeout(gpmu->regmap,
> +					      
> APMU_POWER_STATUS_REG,
> +					       val,
> +					       !(val & BIT(p-
> >bit_hw_pwr_stat)),
> +					       5,
> +					      
> APMU_POWER_TIMEOUT_US);
> +	}
> +
> +	if (ret) {
> +		dev_err(&domain->dev, "Fail to power-off domain:
> %d\n",
> +				spd->pm_index);
> +		return -EBUSY;
> +	}
> +
> +	return 0;
> +}
> +
> +static int spacemit_pd_power_on(struct generic_pm_domain *domain)
> +{
> +	struct spacemit_pm_domain *spd = container_of(domain, struct
> spacemit_pm_domain, genpd);
> +	const struct spacemit_pm_domain_param *p = spd->param;
> +	unsigned int val;
> +	int ret = 0;
> +
> +	regmap_read(gpmu->regmap, APMU_POWER_STATUS_REG, &val);
> +
> +	if (!p->use_hw && (val & BIT(p->bit_pwr_stat))) {
> +		val = BIT(p->bit_isolation);
> +		regmap_clear_bits(gpmu->regmap, p->reg_pwr_ctrl,
> val);
> +		fsleep(15);
> +
> +		val = BIT(p->bit_sleep1) | BIT(p->bit_sleep2);
> +		regmap_clear_bits(gpmu->regmap, p->reg_pwr_ctrl,
> val);
> +		fsleep(15);
> +
> +		ret = regmap_read_poll_timeout(gpmu->regmap,
> +					      
> APMU_POWER_STATUS_REG,
> +					       val,
> +					       !(val & BIT(p-
> >bit_pwr_stat)),
> +					       5,
> +					      
> APMU_POWER_TIMEOUT_US);
> +	}
> +
> +	if (p->use_hw && (val & BIT(p->bit_hw_pwr_stat))) {
> +		val = BIT(p->bit_auto_pwr_on) | BIT(p->bit_hw_mode);
> +		regmap_clear_bits(gpmu->regmap, p->reg_pwr_ctrl,
> val);
> +		fsleep(30);
> +
> +		ret = regmap_read_poll_timeout(gpmu->regmap,
> +					      
> APMU_POWER_STATUS_REG,
> +					       val,
> +					       !(val & BIT(p-
> >bit_hw_pwr_stat)),
> +					       5,
> +					      
> APMU_POWER_TIMEOUT_US);
> +	}
> +
> +	if (ret < 0) {
> +		dev_err(&domain->dev, "power-off domain: %d,
> error\n", spd->pm_index);
> +		return -EBUSY;
> +	}
> +
> +	if (!p->use_hw) {
> +		regmap_set_bits(gpmu->regmap, p->reg_pwr_ctrl,
> BIT(p->bit_sleep1));
> +		fsleep(20);
> +
> +		val = BIT(p->bit_sleep2) | BIT(p->bit_sleep1);
> +		regmap_set_bits(gpmu->regmap, p->reg_pwr_ctrl, val);
> +		fsleep(20);
> +
> +		regmap_set_bits(gpmu->regmap, p->reg_pwr_ctrl,
> BIT(p->bit_isolation));
> +		fsleep(15);
> +
> +		ret = regmap_read_poll_timeout(gpmu->regmap,
> +					      
> APMU_POWER_STATUS_REG,
> +					       val,
> +					       (val & BIT(p-
> >bit_pwr_stat)),
> +					       5,
> +					      
> APMU_POWER_TIMEOUT_US);
> +	} else {
> +		val = BIT(p->bit_auto_pwr_on) | BIT(p->bit_hw_mode);
> +		regmap_set_bits(gpmu->regmap, p->reg_pwr_ctrl, val);
> +		fsleep(300);
> +
> +		ret = regmap_read_poll_timeout(gpmu->regmap,
> +					      
> APMU_POWER_STATUS_REG,
> +					       val,
> +					       (val & BIT(p-
> >bit_hw_pwr_stat)),
> +					       5,
> +					      
> APMU_POWER_TIMEOUT_US);
> +	}
> +
> +	if (ret < 0) {
> +		dev_err(&domain->dev, "power-on domain: %d,
> error\n", spd->pm_index);
> +		return -EBUSY;
> +	}
> +
> +	return 0;
> +}
> +
> +static bool spacemit_pm_get_state(struct spacemit_pmu *pmu,
> +				  struct spacemit_pm_domain *pd)
> +{
> +	const struct spacemit_pm_domain_param *p = pd->param;
> +	u32 reg, bit;
> +
> +	regmap_read(pmu->regmap, APMU_POWER_STATUS_REG, &reg);
> +
> +	bit = p->use_hw ? BIT(pd->param->bit_hw_pwr_stat) :
> +		BIT(pd->param->bit_pwr_stat);
> +
> +	return !!(reg & bit);
> +}
> +
> +static int spacemit_pm_add_one_domain(struct spacemit_pmu *pmu, int
> id,
> +				      const struct
> spacemit_pm_domain_param *param)
> +{
> +	struct spacemit_pm_domain *pd;
> +
> +	pd = devm_kzalloc(pmu->dev, sizeof(*pd), GFP_KERNEL);
> +	if (!pd)
> +		return -ENOMEM;
> +
> +	pd->pm_index        = id;
> +	pd->param           = param;
> +	pd->genpd.name      = param->name;
> +	pd->genpd.power_off = spacemit_pd_power_off;
> +	pd->genpd.power_on  = spacemit_pd_power_on;
> +
> +	pm_genpd_init(&pd->genpd, NULL, !spacemit_pm_get_state(pmu,
> pd));
> +
> +	pmu->domains[id] = pd;
> +
> +	return 0;
> +}
> +
> +static void spacemit_pm_domain_cleanup(struct spacemit_pmu *pmu)
> +{
> +	int i;
> +
> +	for (i = 0; i < pmu->num_domains; i++) {
> +		if (pmu->domains[i])
> +			pm_genpd_remove(&pmu->domains[i]->genpd);
> +	}
> +}
> +
> +static int spacemit_pm_domain_probe(struct platform_device *pdev)
> +{
> +	const struct spacemit_pm_of_data *data;
> +	struct device *dev = &pdev->dev;
> +	struct spacemit_pmu *pmu;
> +	int err, i;
> +
> +	data = device_get_match_data(dev);
> +
> +	pmu = devm_kzalloc(dev, sizeof(*pmu), GFP_KERNEL);
> +	if (!pmu)
> +		return -ENOMEM;
> +
> +	pmu->dev = dev;
> +	pmu->num_domains = data->num_domains;
> +
> +	pmu->regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
> "spacemit,apmu");
> +	if (IS_ERR(pmu->regmap))
> +		return dev_err_probe(dev, PTR_ERR(pmu->regmap),
> "failed to get apmu regmap\n");
> +
> +	pmu->domains = devm_kcalloc(dev, data->num_domains,
> +				    sizeof(*pmu->domains),
> GFP_KERNEL);
> +	if (!pmu->domains)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < data->num_domains; i++) {
> +		err = spacemit_pm_add_one_domain(pmu, i, &data-
> >param[i]);
> +		if (err) {
> +			dev_err(dev, "failed to add domain %d:
> %d\n", i, err);
> +			goto err_out;
> +		}
> +	}
> +
> +	pmu->genpd_data.domains     = (struct generic_pm_domain
> **)pmu->domains;
> +	pmu->genpd_data.num_domains = data->num_domains;
> +
> +	err = of_genpd_add_provider_onecell(dev->of_node, &pmu-
> >genpd_data);
> +	if (err) {
> +		dev_err(dev, "failed to add provider: %d\n", err);
> +		goto err_out;
> +	}
> +
> +	gpmu = pmu;
> +
> +	return 0;
> +
> +err_out:
> +	spacemit_pm_domain_cleanup(pmu);
> +	return err;
> +}
> +
> +static const struct spacemit_pm_domain_param k1_domain_params[] = {
> +	[K1_PMDOMAIN_VPU] = {
> +		.reg_pwr_ctrl		= 0xa8,
> +		.bit_sleep2		= 3,
> +		.bit_sleep1		= 2,
> +		.bit_isolation		= 1,
> +		.bit_pwr_stat		= 1,
> +		.bit_hw_pwr_stat	= 9,
> +		.name			= "vpu",
> +	},
> +	[K1_PMDOMAIN_GPU] = {
> +		.reg_pwr_ctrl		= 0xd0,
> +		.bit_sleep2		= 3,
> +		.bit_sleep1		= 2,
> +		.bit_isolation		= 1,
> +		.bit_pwr_stat		= 0,
> +		.name			= "gpu",
> +	},
> +	[K1_PMDOMAIN_LCD] = {
> +		.reg_pwr_ctrl		= 0x380,
> +		.bit_hw_mode		= 4,
> +		.bit_sleep2		= 3,
> +		.bit_sleep1		= 2,
> +		.bit_isolation		= 1,
> +		.bit_auto_pwr_on	= 0,
> +		.bit_pwr_stat		= 4,
> +		.bit_hw_pwr_stat	= 12,
> +		.use_hw			= 1,
> +		.name			= "lcd",
> +	},
> +	[K1_PMDOMAIN_ISP] = {
> +		.reg_pwr_ctrl		= 0x37c,
> +		.bit_hw_mode		= 4,
> +		.bit_sleep2		= 3,
> +		.bit_sleep1		= 2,
> +		.bit_isolation		= 1,
> +		.bit_auto_pwr_on	= 0,
> +		.bit_pwr_stat		= 2,
> +		.bit_hw_pwr_stat	= 10,
> +		.name			= "isp",
> +	},
> +	[K1_PMDOMAIN_AUDIO] = {
> +		.reg_pwr_ctrl		= 0x378,
> +		.bit_hw_mode		= 4,
> +		.bit_sleep2		= 3,
> +		.bit_sleep1		= 2,
> +		.bit_isolation		= 1,
> +		.bit_auto_pwr_on	= 0,
> +		.bit_pwr_stat		= 3,
> +		.bit_hw_pwr_stat	= 11,
> +		.use_hw			= 1,
> +		.name			= "audio",
> +	},
> +	[K1_PMDOMAIN_GNSS] = {
> +		.reg_pwr_ctrl		= 0x13c,
> +		.bit_hw_mode		= 4,
> +		.bit_sleep2		= 3,
> +		.bit_sleep1		= 2,
> +		.bit_isolation		= 1,
> +		.bit_auto_pwr_on	= 0,
> +		.bit_pwr_stat		= 6,
> +		.bit_hw_pwr_stat	= 14,
> +		.name			= "gnss",
> +	},
> +	[K1_PMDOMAIN_HDMI] = {
> +		.reg_pwr_ctrl		= 0x3f4,
> +		.bit_hw_mode		= 4,
> +		.bit_sleep2		= 3,
> +		.bit_sleep1		= 2,
> +		.bit_isolation		= 1,
> +		.bit_auto_pwr_on	= 0,
> +		.bit_pwr_stat		= 7,
> +		.bit_hw_pwr_stat	= 15,
> +		.use_hw			= 1,
> +		.name			= "hdmi",
> +	},
> +};
> +
> +static const struct spacemit_pm_domain_param k3_domain_params[] = {
> +	[K3_PMDOMAIN_VPU] = {
> +		.bit_auto_pwr_on	= 0,
> +		.bit_isolation		= 1,
> +		.bit_sleep1		= 2,
> +		.bit_sleep2		= 3,
> +		.bit_hw_mode		= 4,
> +		.bit_pwr_stat		= 2,
> +		.bit_hw_pwr_stat	= 9,
> +		.use_hw			= 1,
> +		.reg_pwr_ctrl		= 0xa8,
> +		.name			= "vpu",
> +	},
> +	[K3_PMDOMAIN_GPU] = {
> +		.bit_auto_pwr_on	= 0,
> +		.bit_isolation		= 1,
> +		.bit_sleep1		= 2,
> +		.bit_sleep2		= 3,
> +		.bit_hw_mode		= 4,
> +		.bit_pwr_stat		= 0,
> +		.bit_hw_pwr_stat	= 8,
> +		.use_hw			= 1,
> +		.reg_pwr_ctrl		= 0xd0,
> +		.name			= "gpu",
> +	},
> +	[K3_PMDOMAIN_AUDIO] = {
> +		.bit_auto_pwr_on	= 0,
> +		.bit_isolation		= 1,
> +		.bit_sleep1		= 2,
> +		.bit_sleep2		= 3,
> +		.bit_hw_mode		= 4,
> +		.bit_pwr_stat		= 3,
> +		.reg_pwr_ctrl		= 0x378,
> +		.name			= "audio",
> +	},
> +	[K3_PMDOMAIN_LCD0] = {
> +		.bit_auto_pwr_on	= 0,
> +		.bit_isolation		= 1,
> +		.bit_sleep1		= 2,
> +		.bit_sleep2		= 3,
> +		.bit_hw_mode		= 4,
> +		.bit_pwr_stat		= 4,
> +		.bit_hw_pwr_stat	= 12,
> +		.use_hw			= 1,
> +		.reg_pwr_ctrl		= 0x380,
> +		.name			= "lcd0",
> +	},
> +	[K3_PMDOMAIN_LCD1] = {
> +		.bit_auto_pwr_on	= 0,
> +		.bit_isolation		= 1,
> +		.bit_sleep1		= 2,
> +		.bit_sleep2		= 3,
> +		.bit_hw_mode		= 4,
> +		.bit_pwr_stat		= 5,
> +		.bit_hw_pwr_stat	= 15,
> +		.use_hw			= 1,
> +		.reg_pwr_ctrl		= 0x3f4,
> +		.name			= "lcd1",
> +	},
> +};
> +
> +static const struct spacemit_pm_of_data k1_of_data = {
> +	.num_domains	= ARRAY_SIZE(k1_domain_params),
> +	.param		= k1_domain_params,
> +};
> +
> +static const struct spacemit_pm_of_data k3_of_data = {
> +	.num_domains	= ARRAY_SIZE(k3_domain_params),
> +	.param		= k3_domain_params,
> +};
> +
> +static const struct of_device_id spacemit_pm_domain_dt_match[] = {
> +	{
> +		.compatible = "spacemit,k1-power-controller",
> +		.data = &k1_of_data,
> +	},
> +	{
> +		.compatible = "spacemit,k3-power-controller",
> +		.data = &k3_of_data,
> +	},
> +	{ /* sentinel */ }
> +};
> +
> +static struct platform_driver spacemit_pm_domain_driver = {
> +	.probe = spacemit_pm_domain_probe,
> +	.driver = {
> +		.name           = "spacemit-pm-domain",
> +		.of_match_table = spacemit_pm_domain_dt_match,
> +	},
> +};
> +
> +builtin_platform_driver(spacemit_pm_domain_driver);
> +MODULE_DESCRIPTION("SpacemiT Generic Power Domains driver");
> +MODULE_LICENSE("GPL");

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/3] pmdomain: spacemit: Add power domain driver
  2026-09-18  9:00   ` Icenowy Zheng
@ 2026-09-18 23:01     ` Yixun Lan
  2026-09-19  6:57       ` Icenowy Zheng
  0 siblings, 1 reply; 8+ messages in thread
From: Yixun Lan @ 2026-09-18 23:01 UTC (permalink / raw)
  To: Icenowy Zheng
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
	devicetree, linux-riscv, spacemit, linux-kernel, linux-pm

Hi Icenowy, 

On 17:00 Fri 18 Sep     , Icenowy Zheng wrote:
> 在 2026-09-18五的 02:40 +0000,Yixun Lan写道:
> >   SpacemiT's PMU (Power Management Unit) consist of several power
> > domains
> > which can be managed independently, depending on different
> > application
> > scenario, each domain can be powered on/off for saving power.
> > 
> >   The driver is implemented based on Linux Generic PM Domain
> > framework.
> > From a hardware perspective, either of two distinct power-on
> > sequences
> > are supported, in software mode (SW mode), the driver is responsible
> > for
> > controlling the states of bits such as sleep1, sleep2, isolation and
> > pwr_state, while in hardware mode (HW mode), the PMU hardware will
> > complete
> > the sequence automatically without requiring software intervention.
> 
> I think there also exists solutions for K3 that uses RPMI power
> domains, and let their ESOS firmware to access the hardware.
> 
Yes, I'm aware of that

> What's the relationship of this implementation with the ESOS
> implementation? Should the ESOS part be disabled to use this
> implementation?
> 
I should say, it's a mutually exclusive solution, so yes, the ESOS part
should be disabled in order to use this version

The motivation of this patch is trying to support drm/display driver's
PM requirement, while avoid going with vendor's complicated RPMI solution
which isn't mainline ready

-- 
Yixun Lan (dlan)

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/3] pmdomain: spacemit: Add power domain driver
  2026-09-18 23:01     ` Yixun Lan
@ 2026-09-19  6:57       ` Icenowy Zheng
  2026-09-19  9:59         ` Yixun Lan
  0 siblings, 1 reply; 8+ messages in thread
From: Icenowy Zheng @ 2026-09-19  6:57 UTC (permalink / raw)
  To: Yixun Lan
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
	devicetree, linux-riscv, spacemit, linux-kernel, linux-pm

在 2026-09-18五的 23:01 +0000,Yixun Lan写道:
> Hi Icenowy, 
> 
> On 17:00 Fri 18 Sep     , Icenowy Zheng wrote:
> > 在 2026-09-18五的 02:40 +0000,Yixun Lan写道:
> > >   SpacemiT's PMU (Power Management Unit) consist of several power
> > > domains
> > > which can be managed independently, depending on different
> > > application
> > > scenario, each domain can be powered on/off for saving power.
> > > 
> > >   The driver is implemented based on Linux Generic PM Domain
> > > framework.
> > > From a hardware perspective, either of two distinct power-on
> > > sequences
> > > are supported, in software mode (SW mode), the driver is
> > > responsible
> > > for
> > > controlling the states of bits such as sleep1, sleep2, isolation
> > > and
> > > pwr_state, while in hardware mode (HW mode), the PMU hardware
> > > will
> > > complete
> > > the sequence automatically without requiring software
> > > intervention.
> > 
> > I think there also exists solutions for K3 that uses RPMI power
> > domains, and let their ESOS firmware to access the hardware.
> > 
> Yes, I'm aware of that
> 
> > What's the relationship of this implementation with the ESOS
> > implementation? Should the ESOS part be disabled to use this
> > implementation?
> > 
> I should say, it's a mutually exclusive solution, so yes, the ESOS
> part
> should be disabled in order to use this version
> 
> The motivation of this patch is trying to support drm/display
> driver's
> PM requirement, while avoid going with vendor's complicated RPMI
> solution
> which isn't mainline ready

Is this a long-term solution, or a temporary one?

If it's a temporary conflicting one, I don't think it's worth picking
at all.

Thanks,
Icenowy


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/3] pmdomain: spacemit: Add power domain driver
  2026-09-19  6:57       ` Icenowy Zheng
@ 2026-09-19  9:59         ` Yixun Lan
  0 siblings, 0 replies; 8+ messages in thread
From: Yixun Lan @ 2026-09-19  9:59 UTC (permalink / raw)
  To: Icenowy Zheng
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
	devicetree, linux-riscv, spacemit, linux-kernel, linux-pm

Hi Icenowy,

On 14:57 Sat 19 Sep     , Icenowy Zheng wrote:
> 在 2026-09-18五的 23:01 +0000,Yixun Lan写道:
> > Hi Icenowy, 
> > 
> > On 17:00 Fri 18 Sep     , Icenowy Zheng wrote:
> > > 在 2026-09-18五的 02:40 +0000,Yixun Lan写道:
> > > >   SpacemiT's PMU (Power Management Unit) consist of several power
> > > > domains
> > > > which can be managed independently, depending on different
> > > > application
> > > > scenario, each domain can be powered on/off for saving power.
> > > > 
> > > >   The driver is implemented based on Linux Generic PM Domain
> > > > framework.
> > > > From a hardware perspective, either of two distinct power-on
> > > > sequences
> > > > are supported, in software mode (SW mode), the driver is
> > > > responsible
> > > > for
> > > > controlling the states of bits such as sleep1, sleep2, isolation
> > > > and
> > > > pwr_state, while in hardware mode (HW mode), the PMU hardware
> > > > will
> > > > complete
> > > > the sequence automatically without requiring software
> > > > intervention.
> > > 
> > > I think there also exists solutions for K3 that uses RPMI power
> > > domains, and let their ESOS firmware to access the hardware.
> > > 
> > Yes, I'm aware of that
> > 
> > > What's the relationship of this implementation with the ESOS
> > > implementation? Should the ESOS part be disabled to use this
> > > implementation?
> > > 
> > I should say, it's a mutually exclusive solution, so yes, the ESOS
> > part
> > should be disabled in order to use this version
> > 
> > The motivation of this patch is trying to support drm/display
> > driver's
> > PM requirement, while avoid going with vendor's complicated RPMI
> > solution
> > which isn't mainline ready
> 
> Is this a long-term solution, or a temporary one?
> 
For upstream, I'd say we probably will stick to this solution for
long time, won't say it 'forever', see comment below..

> If it's a temporary conflicting one, I don't think it's worth picking
> at all.
> 
Well, checked current Linux kernel status, there is no RPMI PM solution 
implemented although there is documentation in riscv-rpmi spec[1]

On the other hand, I see no problem to switch to RPMI solution once it
became mature, it's very similar to two solution of clock CLK_CCU vs CLK_RPMI.. 

Link: https://github.com/riscv-non-isa/riscv-rpmi/blob/main/src/srvgrp-device-power.adoc [1]
-- 
Yixun Lan (dlan)

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-09-19  9:59 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-18  2:40 [PATCH 0/3] PM: spacemit: Add power domain support Yixun Lan
2026-09-18  2:40 ` [PATCH 1/3] dt-bindings: power: spacemit: Add power domain controller Yixun Lan
2026-09-18  2:40 ` [PATCH 2/3] pmdomain: spacemit: Add power domain driver Yixun Lan
2026-09-18  9:00   ` Icenowy Zheng
2026-09-18 23:01     ` Yixun Lan
2026-09-19  6:57       ` Icenowy Zheng
2026-09-19  9:59         ` Yixun Lan
2026-09-18  2:40 ` [PATCH 3/3] dts: riscv: spacemit: Add power domain nodes Yixun Lan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®