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

Weiyi Lu weiyi.lu at mediatek.com
Thu Aug 6 05:21:49 EDT 2020


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 at mediatek.com>
---
 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


More information about the linux-arm-kernel mailing list