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...@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

Reply via email to