@@ -20192,7 +20192,9 @@ F: drivers/clk/thead/
F: drivers/mailbox/mailbox-th1520.c
F: drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c
F: drivers/pinctrl/pinctrl-th1520.c
+F: drivers/pmdomain/thead/th1520-pm-domains.c
F: include/dt-bindings/clock/thead,th1520-clk.h
+F: include/dt-bindings/power/thead,th1520-power.h
RNBD BLOCK DRIVERS
M: Md. Haris Iqbal <haris.iqbal@ionos.com>
@@ -16,6 +16,7 @@ source "drivers/pmdomain/st/Kconfig"
source "drivers/pmdomain/starfive/Kconfig"
source "drivers/pmdomain/sunxi/Kconfig"
source "drivers/pmdomain/tegra/Kconfig"
+source "drivers/pmdomain/thead/Kconfig"
source "drivers/pmdomain/ti/Kconfig"
source "drivers/pmdomain/xilinx/Kconfig"
@@ -14,6 +14,7 @@ obj-y += st/
obj-y += starfive/
obj-y += sunxi/
obj-y += tegra/
+obj-y += thead/
obj-y += ti/
obj-y += xilinx/
obj-y += core.o governor.o
new file mode 100644
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config TH1520_PM_DOMAINS
+ bool "Support TH1520 Power Domains"
+ depends on ARCH_THEAD || COMPILE_TEST
+ select REGMAP_MMIO
+ help
+ This driver enables power domain management for the T-HEAD
+ TH-1520 SoC. On this SoC there are number of power domains,
+ which can be managed independently. For example GPU, AUDIO,
+ NPU, DPU reside in their own power domains which can be
+ turned on/off.
new file mode 100644
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_TH1520_PM_DOMAINS) += th1520-pm-domains.o
new file mode 100644
@@ -0,0 +1,195 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Author: Michal Wilczynski <m.wilczynski@samsung.com>
+ */
+
+#include <linux/mfd/syscon.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_domain.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/power/thead,th1520-power.h>
+
+/* register offset in VOSYS_REGMAP */
+#define TH1520_GPU_RST_CFG 0x0
+#define TH1520_GPU_RST_CFG_MASK GENMASK(2, 0)
+
+/* register values */
+#define TH1520_GPU_SW_GPU_RST BIT(0)
+#define TH1520_GPU_SW_CLKGEN_RST BIT(1)
+
+struct th1520_power_domain {
+ struct regmap *reg;
+ struct generic_pm_domain genpd;
+ u32 rsrc;
+};
+
+struct th1520_power_info {
+ char *name;
+ u32 rsrc;
+};
+
+static const struct th1520_power_info th1520_pd_ranges[] = {
+ { "gpu", TH1520_AON_GPU_PD }
+};
+
+static inline struct th1520_power_domain *
+to_th1520_power_domain(struct generic_pm_domain *genpd)
+{
+ return container_of(genpd, struct th1520_power_domain, genpd);
+}
+
+static void th1520_rst_gpu_enable(struct regmap *reg)
+{
+ int val;
+
+ /* if the GPU is not in a reset state it, put it into one */
+ regmap_read(reg, TH1520_GPU_RST_CFG, &val);
+ if (val) {
+ regmap_update_bits(reg, TH1520_GPU_RST_CFG,
+ TH1520_GPU_RST_CFG_MASK, 0x0);
+ }
+
+ /* rst gpu clkgen */
+ regmap_set_bits(reg, TH1520_GPU_RST_CFG, TH1520_GPU_SW_CLKGEN_RST);
+ /* rst gpu */
+ regmap_set_bits(reg, TH1520_GPU_RST_CFG, TH1520_GPU_SW_GPU_RST);
+}
+
+static void th1520_rst_gpu_disable(struct regmap *reg)
+{
+ regmap_update_bits(reg, TH1520_GPU_RST_CFG, TH1520_GPU_RST_CFG_MASK, 0x0);
+}
+
+static int th1520_pd_power_on(struct generic_pm_domain *domain)
+{
+ struct th1520_power_domain *pd = to_th1520_power_domain(domain);
+
+ /* The missing component here is the call to E902 core through the
+ * AON protocol using hardware mailbox.
+ */
+
+ /* Initially after the power up the GPU and GPU clocks are
+ * in the reset state. Get them from that state to normal operation.
+ */
+ th1520_rst_gpu_enable(pd->reg);
+
+ return 0;
+}
+
+static int th1520_pd_power_off(struct generic_pm_domain *domain)
+{
+ struct th1520_power_domain *pd = to_th1520_power_domain(domain);
+
+ /* The missing component here is the call to E902 core through the
+ * AON protocol using hardware mailbox.
+ */
+
+ /* Put the GPU into reset state after powering it off */
+ th1520_rst_gpu_disable(pd->reg);
+
+ return 0;
+}
+
+static struct generic_pm_domain *th1520_pd_xlate(const struct of_phandle_args *spec,
+ void *data)
+{
+ struct generic_pm_domain *domain = ERR_PTR(-ENOENT);
+ struct genpd_onecell_data *pd_data = data;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(th1520_pd_ranges); i++) {
+ struct th1520_power_domain *pd;
+
+ pd = to_th1520_power_domain(pd_data->domains[i]);
+ if (pd->rsrc == spec->args[0]) {
+ domain = &pd->genpd;
+ break;
+ }
+ }
+
+ return domain;
+}
+
+static struct th1520_power_domain *
+th1520_add_pm_domain(struct device *dev, const struct th1520_power_info *pi)
+{
+ struct th1520_power_domain *pd;
+ int ret;
+
+ pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+ if (!pd)
+ return ERR_PTR(-ENOMEM);
+
+ pd->rsrc = pi->rsrc;
+ pd->genpd.power_on = th1520_pd_power_on;
+ pd->genpd.power_off = th1520_pd_power_off;
+ pd->genpd.name = pi->name;
+
+ ret = pm_genpd_init(&pd->genpd, NULL, true);
+ if (ret) {
+ devm_kfree(dev, pd);
+ return ERR_PTR(ret);
+ }
+
+ return pd;
+}
+
+static int th1520_pd_probe(struct platform_device *pdev)
+{
+ struct generic_pm_domain **domains;
+ struct genpd_onecell_data *pd_data;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct regmap *reg;
+ int i;
+
+ reg = syscon_regmap_lookup_by_phandle(np, "thead,vosys-regmap");
+ if (IS_ERR(reg))
+ return PTR_ERR(reg);
+
+ domains = devm_kcalloc(dev, ARRAY_SIZE(th1520_pd_ranges),
+ sizeof(*domains), GFP_KERNEL);
+ if (!domains)
+ return -ENOMEM;
+
+ pd_data = devm_kzalloc(dev, sizeof(*pd_data), GFP_KERNEL);
+ if (!pd_data)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(th1520_pd_ranges); i++) {
+ struct th1520_power_domain *pd;
+
+ pd = th1520_add_pm_domain(dev, &th1520_pd_ranges[i]);
+ if (IS_ERR_OR_NULL(pd))
+ continue;
+
+ pd->reg = reg;
+ domains[i] = &pd->genpd;
+ dev_dbg(dev, "added power domain %s\n", pd->genpd.name);
+ }
+
+ pd_data->domains = domains;
+ pd_data->num_domains = ARRAY_SIZE(th1520_pd_ranges);
+ pd_data->xlate = th1520_pd_xlate;
+
+ return of_genpd_add_provider_onecell(dev->of_node, pd_data);
+}
+
+static const struct of_device_id th1520_pd_match[] = {
+ { .compatible = "thead,th1520-pd",},
+ { /* sentinel */ }
+};
+
+static struct platform_driver th1520_pd_driver = {
+ .driver = {
+ .name = "th1520-pd",
+ .of_match_table = th1520_pd_match,
+ },
+ .probe = th1520_pd_probe,
+};
+builtin_platform_driver(th1520_pd_driver);
new file mode 100644
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2022 Alibaba Group Holding Limited.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Author: Michal Wilczynski <m.wilczynski@samsung.com>
+ */
+
+#ifndef __DT_BINDINGS_POWER_TH1520_H
+#define __DT_BINDINGS_POWER_TH1520_H
+
+#define TH1520_AON_AUDIO_PD 0
+#define TH1520_AON_VDEC_PD 1
+#define TH1520_AON_NPU_PD 2
+#define TH1520_AON_VENC_PD 3
+#define TH1520_AON_GPU_PD 4
+#define TH1520_AON_DSP0_PD 5
+#define TH1520_AON_DSP1_PD 6
+
+#endif
The T-Head TH1520 SoC contains multiple power islands that can be programmatically turned on and off using the AON (Always-On) protocol and a hardware mailbox [1]. The relevant mailbox driver has already been merged into the mainline kernel in commit 5d4d263e1c6b ("mailbox: Introduce support for T-head TH1520 Mailbox driver"); however, the AON implementation is still under development. This commit introduces a skeleton power-domain driver for the TH1520 SoC, designed to be easily extended to work with the AON protocol in the future. Currently, it only supports the GPU. Since there is no mechanism yet to turn the GPU power island on, the driver will only set the relevant registers to bring the GPU out of the reset state. This should be done after the power-up sequence requested through the mailbox is completed. Link: https://openbeagle.org/beaglev-ahead/beaglev-ahead/-/blob/main/docs/TH1520%20System%20User%20Manual.pdf [1] Signed-off-by: Michal Wilczynski <m.wilczynski@samsung.com> --- MAINTAINERS | 2 + drivers/pmdomain/Kconfig | 1 + drivers/pmdomain/Makefile | 1 + drivers/pmdomain/thead/Kconfig | 12 ++ drivers/pmdomain/thead/Makefile | 2 + drivers/pmdomain/thead/th1520-pm-domains.c | 195 ++++++++++++++++++ .../dt-bindings/power/thead,th1520-power.h | 19 ++ 7 files changed, 232 insertions(+) create mode 100644 drivers/pmdomain/thead/Kconfig create mode 100644 drivers/pmdomain/thead/Makefile create mode 100644 drivers/pmdomain/thead/th1520-pm-domains.c create mode 100644 include/dt-bindings/power/thead,th1520-power.h