[PATCH v17 06/12] soc: mediatek: Add support for hierarchical scpsys device node

From: Weiyi Lu
Date: Thu Aug 06 2020 - 05:34:56 EST


Try to list all the power domains of under power controller
node to show the dependency between each power domain directly
instead of filling the dependency in scp_soc_data.
And could be more clearly to group subsys clocks into power domain
sub node to introduce subsys clocks of bus protection in next patch.

Signed-off-by: Weiyi Lu <weiyi.lu@xxxxxxxxxxxx>
---
drivers/soc/mediatek/mtk-scpsys.c | 103 +++++++++++++++++++++++++++++++++++---
1 file changed, 95 insertions(+), 8 deletions(-)

diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
index 5a2c323..502b66f 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -182,11 +182,13 @@ struct scp {
struct regmap *infracfg;
struct regmap *smi_common;
struct scp_ctrl_reg ctrl_reg;
+ struct list_head dep_links;
};

struct scp_subdomain {
int origin;
int subdomain;
+ struct list_head list;
};

struct scp_soc_data {
@@ -513,6 +515,79 @@ static int init_basic_clks(struct platform_device *pdev, struct clk **clk,
return 0;
}

+static int scpsys_get_domain_id(struct device_node *node, u32 *id)
+{
+ int ret;
+
+ ret = of_property_read_u32(node, "reg", id);
+ if (ret)
+ pr_err("%pOFn: failed to retrieve domain id, ret=%d\n", node, ret);
+
+ return ret;
+}
+
+static int scpsys_get_domain(struct platform_device *pdev, struct scp *scp,
+ struct device_node *node, const struct scp_domain_data *data)
+{
+ struct scp_subdomain *dep_node;
+ struct device_node *sub;
+ u32 parent_id, child_id;
+ int ret;
+
+ ret = scpsys_get_domain_id(node, &parent_id);
+ if (ret)
+ return ret;
+
+ for_each_child_of_node(node, sub) {
+ ret = scpsys_get_domain_id(sub, &child_id);
+ if (ret)
+ goto out;
+
+ dep_node = devm_kzalloc(&pdev->dev, sizeof(*dep_node), GFP_KERNEL);
+ if (!dep_node) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ dep_node->origin = parent_id;
+ dep_node->subdomain = child_id;
+ list_add(&dep_node->list, &scp->dep_links);
+
+ scpsys_get_domain(pdev, scp, sub, data);
+ }
+
+ return 0;
+
+out:
+ of_node_put(sub);
+ return ret;
+}
+
+static int traverse_scp(struct platform_device *pdev, struct scp *scp,
+ const struct scp_domain_data *scp_domain_data)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *sub;
+ int ret;
+
+ INIT_LIST_HEAD(&scp->dep_links);
+
+ for_each_available_child_of_node(np, sub) {
+ ret = scpsys_get_domain(pdev, scp, sub, scp_domain_data);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to handle node %pOFn: %d\n", sub, ret);
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ of_node_put(sub);
+ return ret;
+}
+
static struct scp *init_scp(struct platform_device *pdev,
const struct scp_domain_data *scp_domain_data, int num,
const struct scp_ctrl_reg *scp_ctrl_reg)
@@ -582,6 +657,10 @@ static struct scp *init_scp(struct platform_device *pdev,

pd_data->num_domains = num;

+ ret = traverse_scp(pdev, scp, scp_domain_data);
+ if (ret)
+ return ERR_PTR(ret);
+
for (i = 0; i < num; i++) {
struct scp_domain *scpd = &scp->domains[i];
struct generic_pm_domain *genpd = &scpd->genpd;
@@ -1208,7 +1287,7 @@ static int scpsys_probe(struct platform_device *pdev)
const struct scp_soc_data *soc;
struct scp *scp;
struct genpd_onecell_data *pd_data;
- int i, ret;
+ int i, ret = 0;

soc = of_device_get_match_data(&pdev->dev);

@@ -1220,15 +1299,23 @@ static int scpsys_probe(struct platform_device *pdev)

pd_data = &scp->pd_data;

- for (i = 0, sd = soc->subdomains; i < soc->num_subdomains; i++, sd++) {
- ret = pm_genpd_add_subdomain(pd_data->domains[sd->origin],
- pd_data->domains[sd->subdomain]);
- if (ret && IS_ENABLED(CONFIG_PM))
- dev_err(&pdev->dev, "Failed to add subdomain: %d\n",
- ret);
+ if (soc->subdomains && soc->num_subdomains) {
+ for (i = 0, sd = soc->subdomains; i < soc->num_subdomains; i++, sd++) {
+ ret = pm_genpd_add_subdomain(pd_data->domains[sd->origin],
+ pd_data->domains[sd->subdomain]);
+ if (ret && IS_ENABLED(CONFIG_PM))
+ dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
+ }
+ } else {
+ list_for_each_entry(sd, &scp->dep_links, list) {
+ ret = pm_genpd_add_subdomain(pd_data->domains[sd->origin],
+ pd_data->domains[sd->subdomain]);
+ if (ret && IS_ENABLED(CONFIG_PM))
+ dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
+ }
}

- return 0;
+ return ret;
}

static struct platform_driver scpsys_drv = {
--
1.8.1.1.dirty