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