diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml index 2ff246cf8b81..929b7ef9c1bc 100644 --- a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml +++ b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml @@ -24,6 +24,8 @@ properties: - qcom,msm8917-rpmpd - qcom,msm8939-rpmpd - qcom,msm8953-rpmpd + - qcom,msm8974-rpmpd + - qcom,msm8974pro-pma8084-rpmpd - qcom,msm8976-rpmpd - qcom,msm8994-rpmpd - qcom,msm8996-rpmpd diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx8mp-hdmi-blk-ctrl.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx8mp-hdmi-blk-ctrl.yaml index 1be4ce2a45e8..bd1cdaa4f54b 100644 --- a/Documentation/devicetree/bindings/soc/imx/fsl,imx8mp-hdmi-blk-ctrl.yaml +++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx8mp-hdmi-blk-ctrl.yaml @@ -27,8 +27,8 @@ properties: const: 1 power-domains: - minItems: 8 - maxItems: 8 + minItems: 10 + maxItems: 10 power-domain-names: items: @@ -40,10 +40,12 @@ properties: - const: trng - const: hdmi-tx - const: hdmi-tx-phy + - const: hdcp + - const: hrv clocks: - minItems: 4 - maxItems: 4 + minItems: 5 + maxItems: 5 clock-names: items: @@ -51,6 +53,7 @@ properties: - const: axi - const: ref_266m - const: ref_24m + - const: fdcc interconnects: maxItems: 3 @@ -82,12 +85,15 @@ examples: clocks = <&clk IMX8MP_CLK_HDMI_APB>, <&clk IMX8MP_CLK_HDMI_ROOT>, <&clk IMX8MP_CLK_HDMI_REF_266M>, - <&clk IMX8MP_CLK_HDMI_24M>; - clock-names = "apb", "axi", "ref_266m", "ref_24m"; + <&clk IMX8MP_CLK_HDMI_24M>, + <&clk IMX8MP_CLK_HDMI_FDCC_TST>; + clock-names = "apb", "axi", "ref_266m", "ref_24m", "fdcc"; power-domains = <&pgc_hdmimix>, <&pgc_hdmimix>, <&pgc_hdmimix>, <&pgc_hdmimix>, <&pgc_hdmimix>, <&pgc_hdmimix>, - <&pgc_hdmimix>, <&pgc_hdmi_phy>; + <&pgc_hdmimix>, <&pgc_hdmi_phy>, + <&pgc_hdmimix>, <&pgc_hdmimix>; power-domain-names = "bus", "irqsteer", "lcdif", "pai", "pvi", "trng", - "hdmi-tx", "hdmi-tx-phy"; + "hdmi-tx", "hdmi-tx-phy", + "hdcp", "hrv"; #power-domain-cells = <1>; }; diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c index 44ec20918a4d..327d168dd37a 100644 --- a/drivers/base/power/common.c +++ b/drivers/base/power/common.c @@ -167,6 +167,115 @@ struct device *dev_pm_domain_attach_by_name(struct device *dev, } EXPORT_SYMBOL_GPL(dev_pm_domain_attach_by_name); +/** + * dev_pm_domain_attach_list - Associate a device with its PM domains. + * @dev: The device used to lookup the PM domains for. + * @data: The data used for attaching to the PM domains. + * @list: An out-parameter with an allocated list of attached PM domains. + * + * This function helps to attach a device to its multiple PM domains. The + * caller, which is typically a driver's probe function, may provide a list of + * names for the PM domains that we should try to attach the device to, but it + * may also provide an empty list, in case the attach should be done for all of + * the available PM domains. + * + * Callers must ensure proper synchronization of this function with power + * management callbacks. + * + * Returns the number of attached PM domains or a negative error code in case of + * a failure. Note that, to detach the list of PM domains, the driver shall call + * dev_pm_domain_detach_list(), typically during the remove phase. + */ +int dev_pm_domain_attach_list(struct device *dev, + const struct dev_pm_domain_attach_data *data, + struct dev_pm_domain_list **list) +{ + struct device_node *np = dev->of_node; + struct dev_pm_domain_list *pds; + struct device *pd_dev = NULL; + int ret, i, num_pds = 0; + bool by_id = true; + u32 pd_flags = data ? data->pd_flags : 0; + u32 link_flags = pd_flags & PD_FLAG_NO_DEV_LINK ? 0 : + DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME; + + if (dev->pm_domain) + return -EEXIST; + + /* For now this is limited to OF based platforms. */ + if (!np) + return 0; + + if (data && data->pd_names) { + num_pds = data->num_pd_names; + by_id = false; + } else { + num_pds = of_count_phandle_with_args(np, "power-domains", + "#power-domain-cells"); + } + + if (num_pds <= 0) + return 0; + + pds = devm_kzalloc(dev, sizeof(*pds), GFP_KERNEL); + if (!pds) + return -ENOMEM; + + pds->pd_devs = devm_kcalloc(dev, num_pds, sizeof(*pds->pd_devs), + GFP_KERNEL); + if (!pds->pd_devs) + return -ENOMEM; + + pds->pd_links = devm_kcalloc(dev, num_pds, sizeof(*pds->pd_links), + GFP_KERNEL); + if (!pds->pd_links) + return -ENOMEM; + + if (link_flags && pd_flags & PD_FLAG_DEV_LINK_ON) + link_flags |= DL_FLAG_RPM_ACTIVE; + + for (i = 0; i < num_pds; i++) { + if (by_id) + pd_dev = dev_pm_domain_attach_by_id(dev, i); + else + pd_dev = dev_pm_domain_attach_by_name(dev, + data->pd_names[i]); + if (IS_ERR_OR_NULL(pd_dev)) { + ret = pd_dev ? PTR_ERR(pd_dev) : -ENODEV; + goto err_attach; + } + + if (link_flags) { + struct device_link *link; + + link = device_link_add(dev, pd_dev, link_flags); + if (!link) { + ret = -ENODEV; + goto err_link; + } + + pds->pd_links[i] = link; + } + + pds->pd_devs[i] = pd_dev; + } + + pds->num_pds = num_pds; + *list = pds; + return num_pds; + +err_link: + dev_pm_domain_detach(pd_dev, true); +err_attach: + while (--i >= 0) { + if (pds->pd_links[i]) + device_link_del(pds->pd_links[i]); + dev_pm_domain_detach(pds->pd_devs[i], true); + } + return ret; +} +EXPORT_SYMBOL_GPL(dev_pm_domain_attach_list); + /** * dev_pm_domain_detach - Detach a device from its PM domain. * @dev: Device to detach. @@ -187,6 +296,31 @@ void dev_pm_domain_detach(struct device *dev, bool power_off) } EXPORT_SYMBOL_GPL(dev_pm_domain_detach); +/** + * dev_pm_domain_detach_list - Detach a list of PM domains. + * @list: The list of PM domains to detach. + * + * This function reverse the actions from dev_pm_domain_attach_list(). + * Typically it should be invoked during the remove phase from drivers. + * + * Callers must ensure proper synchronization of this function with power + * management callbacks. + */ +void dev_pm_domain_detach_list(struct dev_pm_domain_list *list) +{ + int i; + + if (!list) + return; + + for (i = 0; i < list->num_pds; i++) { + if (list->pd_links[i]) + device_link_del(list->pd_links[i]); + dev_pm_domain_detach(list->pd_devs[i], true); + } +} +EXPORT_SYMBOL_GPL(dev_pm_domain_detach_list); + /** * dev_pm_domain_start - Start the device through its PM domain. * @dev: Device to start. diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index a712dd4f02a5..ce206b709754 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -114,7 +115,8 @@ static void venus_sys_error_handler(struct work_struct *work) pm_runtime_put_sync(core->dev); for (i = 0; i < max_attempts; i++) { - if (!core->pmdomains[0] || !pm_runtime_active(core->pmdomains[0])) + if (!core->pmdomains || + !pm_runtime_active(core->pmdomains->pd_devs[0])) break; usleep_range(1000, 1500); } @@ -705,7 +707,7 @@ static const struct venus_resources sdm845_res_v2 = { .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" }, .vcodec1_clks = { "vcodec1_core", "vcodec1_bus" }, .vcodec_clks_num = 2, - .vcodec_pmdomains = { "venus", "vcodec0", "vcodec1" }, + .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0", "vcodec1" }, .vcodec_pmdomains_num = 3, .opp_pmdomain = (const char *[]) { "cx", NULL }, .vcodec_num = 2, @@ -754,7 +756,7 @@ static const struct venus_resources sc7180_res = { .clks_num = 3, .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" }, .vcodec_clks_num = 2, - .vcodec_pmdomains = { "venus", "vcodec0" }, + .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, .vcodec_pmdomains_num = 2, .opp_pmdomain = (const char *[]) { "cx", NULL }, .vcodec_num = 1, @@ -811,7 +813,7 @@ static const struct venus_resources sm8250_res = { .resets_num = 2, .vcodec0_clks = { "vcodec0_core" }, .vcodec_clks_num = 1, - .vcodec_pmdomains = { "venus", "vcodec0" }, + .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, .vcodec_pmdomains_num = 2, .opp_pmdomain = (const char *[]) { "mx", NULL }, .vcodec_num = 1, @@ -870,7 +872,7 @@ static const struct venus_resources sc7280_res = { .clks_num = 3, .vcodec0_clks = {"vcodec_core", "vcodec_bus"}, .vcodec_clks_num = 2, - .vcodec_pmdomains = { "venus", "vcodec0" }, + .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, .vcodec_pmdomains_num = 2, .opp_pmdomain = (const char *[]) { "cx", NULL }, .vcodec_num = 1, diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 4a633261ece4..7ef341bf21cc 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -25,7 +25,6 @@ #define VIDC_CLKS_NUM_MAX 4 #define VIDC_VCODEC_CLKS_NUM_MAX 2 -#define VIDC_PMDOMAINS_NUM_MAX 3 #define VIDC_RESETS_NUM_MAX 2 extern int venus_fw_debug; @@ -72,7 +71,7 @@ struct venus_resources { const char * const vcodec0_clks[VIDC_VCODEC_CLKS_NUM_MAX]; const char * const vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX]; unsigned int vcodec_clks_num; - const char * const vcodec_pmdomains[VIDC_PMDOMAINS_NUM_MAX]; + const char **vcodec_pmdomains; unsigned int vcodec_pmdomains_num; const char **opp_pmdomain; unsigned int vcodec_num; @@ -134,7 +133,7 @@ struct venus_format { * @video_path: an interconnect handle to video to/from memory path * @cpucfg_path: an interconnect handle to cpu configuration path * @has_opp_table: does OPP table exist - * @pmdomains: an array of pmdomains struct device pointers + * @pmdomains: a pointer to a list of pmdomains * @opp_dl_venus: an device-link for device OPP * @opp_pmdomain: an OPP power-domain * @resets: an array of reset signals @@ -187,7 +186,7 @@ struct venus_core { struct icc_path *video_path; struct icc_path *cpucfg_path; bool has_opp_table; - struct device *pmdomains[VIDC_PMDOMAINS_NUM_MAX]; + struct dev_pm_domain_list *pmdomains; struct device_link *opp_dl_venus; struct device *opp_pmdomain; struct reset_control *resets[VIDC_RESETS_NUM_MAX]; diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index a1b127caa90a..502822059498 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -455,7 +455,7 @@ static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask) if (ret) return ret; - ret = pm_runtime_put_sync(core->pmdomains[1]); + ret = pm_runtime_put_sync(core->pmdomains->pd_devs[1]); if (ret < 0) return ret; } @@ -471,7 +471,7 @@ static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask) if (ret) return ret; - ret = pm_runtime_put_sync(core->pmdomains[2]); + ret = pm_runtime_put_sync(core->pmdomains->pd_devs[2]); if (ret < 0) return ret; } @@ -484,7 +484,7 @@ static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask) int ret; if (coreid_mask & VIDC_CORE_ID_1) { - ret = pm_runtime_get_sync(core->pmdomains[1]); + ret = pm_runtime_get_sync(core->pmdomains->pd_devs[1]); if (ret < 0) return ret; @@ -502,7 +502,7 @@ static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask) } if (coreid_mask & VIDC_CORE_ID_2) { - ret = pm_runtime_get_sync(core->pmdomains[2]); + ret = pm_runtime_get_sync(core->pmdomains->pd_devs[2]); if (ret < 0) return ret; @@ -860,19 +860,18 @@ static int vcodec_domains_get(struct venus_core *core) struct device **opp_virt_dev; struct device *dev = core->dev; const struct venus_resources *res = core->res; - struct device *pd; - unsigned int i; + struct dev_pm_domain_attach_data vcodec_data = { + .pd_names = res->vcodec_pmdomains, + .num_pd_names = res->vcodec_pmdomains_num, + .pd_flags = PD_FLAG_NO_DEV_LINK, + }; if (!res->vcodec_pmdomains_num) goto skip_pmdomains; - for (i = 0; i < res->vcodec_pmdomains_num; i++) { - pd = dev_pm_domain_attach_by_name(dev, - res->vcodec_pmdomains[i]); - if (IS_ERR_OR_NULL(pd)) - return pd ? PTR_ERR(pd) : -ENODATA; - core->pmdomains[i] = pd; - } + ret = dev_pm_domain_attach_list(dev, &vcodec_data, &core->pmdomains); + if (ret < 0) + return ret; skip_pmdomains: if (!core->res->opp_pmdomain) @@ -896,30 +895,14 @@ skip_pmdomains: return 0; opp_attach_err: - for (i = 0; i < res->vcodec_pmdomains_num; i++) { - if (IS_ERR_OR_NULL(core->pmdomains[i])) - continue; - dev_pm_domain_detach(core->pmdomains[i], true); - } - + dev_pm_domain_detach_list(core->pmdomains); return ret; } static void vcodec_domains_put(struct venus_core *core) { - const struct venus_resources *res = core->res; - unsigned int i; + dev_pm_domain_detach_list(core->pmdomains); - if (!res->vcodec_pmdomains_num) - goto skip_pmdomains; - - for (i = 0; i < res->vcodec_pmdomains_num; i++) { - if (IS_ERR_OR_NULL(core->pmdomains[i])) - continue; - dev_pm_domain_detach(core->pmdomains[i], true); - } - -skip_pmdomains: if (!core->has_opp_table) return; @@ -1035,7 +1018,8 @@ static void core_put_v4(struct venus_core *core) static int core_power_v4(struct venus_core *core, int on) { struct device *dev = core->dev; - struct device *pmctrl = core->pmdomains[0]; + struct device *pmctrl = core->pmdomains ? + core->pmdomains->pd_devs[0] : NULL; int ret = 0; if (on == POWER_ON) { diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c index 18e232b5ed53..4215ffd9b11c 100644 --- a/drivers/pmdomain/core.c +++ b/drivers/pmdomain/core.c @@ -310,73 +310,103 @@ static int genpd_xlate_performance_state(struct generic_pm_domain *genpd, pstate); } +static int _genpd_set_performance_state(struct generic_pm_domain *genpd, + unsigned int state, int depth); + +static void _genpd_rollback_parent_state(struct gpd_link *link, int depth) +{ + struct generic_pm_domain *parent = link->parent; + int parent_state; + + genpd_lock_nested(parent, depth + 1); + + parent_state = link->prev_performance_state; + link->performance_state = parent_state; + + parent_state = _genpd_reeval_performance_state(parent, parent_state); + if (_genpd_set_performance_state(parent, parent_state, depth + 1)) { + pr_err("%s: Failed to roll back to %d performance state\n", + parent->name, parent_state); + } + + genpd_unlock(parent); +} + +static int _genpd_set_parent_state(struct generic_pm_domain *genpd, + struct gpd_link *link, + unsigned int state, int depth) +{ + struct generic_pm_domain *parent = link->parent; + int parent_state, ret; + + /* Find parent's performance state */ + ret = genpd_xlate_performance_state(genpd, parent, state); + if (unlikely(ret < 0)) + return ret; + + parent_state = ret; + + genpd_lock_nested(parent, depth + 1); + + link->prev_performance_state = link->performance_state; + link->performance_state = parent_state; + + parent_state = _genpd_reeval_performance_state(parent, parent_state); + ret = _genpd_set_performance_state(parent, parent_state, depth + 1); + if (ret) + link->performance_state = link->prev_performance_state; + + genpd_unlock(parent); + + return ret; +} + static int _genpd_set_performance_state(struct generic_pm_domain *genpd, unsigned int state, int depth) { - struct generic_pm_domain *parent; - struct gpd_link *link; - int parent_state, ret; + struct gpd_link *link = NULL; + int ret; if (state == genpd->performance_state) return 0; - /* Propagate to parents of genpd */ - list_for_each_entry(link, &genpd->child_links, child_node) { - parent = link->parent; - - /* Find parent's performance state */ - ret = genpd_xlate_performance_state(genpd, parent, state); - if (unlikely(ret < 0)) - goto err; - - parent_state = ret; - - genpd_lock_nested(parent, depth + 1); - - link->prev_performance_state = link->performance_state; - link->performance_state = parent_state; - parent_state = _genpd_reeval_performance_state(parent, - parent_state); - ret = _genpd_set_performance_state(parent, parent_state, depth + 1); - if (ret) - link->performance_state = link->prev_performance_state; - - genpd_unlock(parent); - - if (ret) - goto err; + /* When scaling up, propagate to parents first in normal order */ + if (state > genpd->performance_state) { + list_for_each_entry(link, &genpd->child_links, child_node) { + ret = _genpd_set_parent_state(genpd, link, state, depth); + if (ret) + goto rollback_parents_up; + } } if (genpd->set_performance_state) { ret = genpd->set_performance_state(genpd, state); - if (ret) - goto err; + if (ret) { + if (link) + goto rollback_parents_up; + return ret; + } + } + + /* When scaling down, propagate to parents last in reverse order */ + if (state < genpd->performance_state) { + list_for_each_entry_reverse(link, &genpd->child_links, child_node) { + ret = _genpd_set_parent_state(genpd, link, state, depth); + if (ret) + goto rollback_parents_down; + } } genpd->performance_state = state; return 0; -err: - /* Encountered an error, lets rollback */ - list_for_each_entry_continue_reverse(link, &genpd->child_links, - child_node) { - parent = link->parent; - - genpd_lock_nested(parent, depth + 1); - - parent_state = link->prev_performance_state; - link->performance_state = parent_state; - - parent_state = _genpd_reeval_performance_state(parent, - parent_state); - if (_genpd_set_performance_state(parent, parent_state, depth + 1)) { - pr_err("%s: Failed to roll back to %d performance state\n", - parent->name, parent_state); - } - - genpd_unlock(parent); - } - +rollback_parents_up: + list_for_each_entry_continue_reverse(link, &genpd->child_links, child_node) + _genpd_rollback_parent_state(link, depth); + return ret; +rollback_parents_down: + list_for_each_entry_continue(link, &genpd->child_links, child_node) + _genpd_rollback_parent_state(link, depth); return ret; } @@ -1100,6 +1130,7 @@ static int __init genpd_power_off_unused(void) return 0; } + pr_info("genpd: Disabling unused power domains\n"); mutex_lock(&gpd_list_lock); list_for_each_entry(genpd, &gpd_list, gpd_list_node) @@ -2235,7 +2266,7 @@ static DEFINE_MUTEX(of_genpd_mutex); * to be a valid pointer to struct generic_pm_domain. */ static struct generic_pm_domain *genpd_xlate_simple( - struct of_phandle_args *genpdspec, + const struct of_phandle_args *genpdspec, void *data) { return data; @@ -2252,7 +2283,7 @@ static struct generic_pm_domain *genpd_xlate_simple( * the genpd_onecell_data struct when registering the provider. */ static struct generic_pm_domain *genpd_xlate_onecell( - struct of_phandle_args *genpdspec, + const struct of_phandle_args *genpdspec, void *data) { struct genpd_onecell_data *genpd_data = data; @@ -2495,7 +2526,7 @@ EXPORT_SYMBOL_GPL(of_genpd_del_provider); * on failure. */ static struct generic_pm_domain *genpd_get_from_provider( - struct of_phandle_args *genpdspec) + const struct of_phandle_args *genpdspec) { struct generic_pm_domain *genpd = ERR_PTR(-ENOENT); struct of_genpd_provider *provider; @@ -2526,7 +2557,7 @@ static struct generic_pm_domain *genpd_get_from_provider( * Looks-up an I/O PM domain based upon phandle args provided and adds * the device to the PM domain. Returns a negative error code on failure. */ -int of_genpd_add_device(struct of_phandle_args *genpdspec, struct device *dev) +int of_genpd_add_device(const struct of_phandle_args *genpdspec, struct device *dev) { struct generic_pm_domain *genpd; int ret; @@ -2560,8 +2591,8 @@ EXPORT_SYMBOL_GPL(of_genpd_add_device); * provided and adds the subdomain to the parent PM domain. Returns a * negative error code on failure. */ -int of_genpd_add_subdomain(struct of_phandle_args *parent_spec, - struct of_phandle_args *subdomain_spec) +int of_genpd_add_subdomain(const struct of_phandle_args *parent_spec, + const struct of_phandle_args *subdomain_spec) { struct generic_pm_domain *parent, *subdomain; int ret; @@ -2598,8 +2629,8 @@ EXPORT_SYMBOL_GPL(of_genpd_add_subdomain); * provided and removes the subdomain from the parent PM domain. Returns a * negative error code on failure. */ -int of_genpd_remove_subdomain(struct of_phandle_args *parent_spec, - struct of_phandle_args *subdomain_spec) +int of_genpd_remove_subdomain(const struct of_phandle_args *parent_spec, + const struct of_phandle_args *subdomain_spec) { struct generic_pm_domain *parent, *subdomain; int ret; diff --git a/drivers/pmdomain/imx/imx8m-blk-ctrl.c b/drivers/pmdomain/imx/imx8m-blk-ctrl.c index 1341a707f61b..ca942d7929c2 100644 --- a/drivers/pmdomain/imx/imx8m-blk-ctrl.c +++ b/drivers/pmdomain/imx/imx8m-blk-ctrl.c @@ -258,11 +258,14 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev) domain->power_dev = dev_pm_domain_attach_by_name(dev, data->gpc_name); - if (IS_ERR(domain->power_dev)) { - dev_err_probe(dev, PTR_ERR(domain->power_dev), + if (IS_ERR_OR_NULL(domain->power_dev)) { + if (!domain->power_dev) + ret = -ENODEV; + else + ret = PTR_ERR(domain->power_dev); + dev_err_probe(dev, ret, "failed to attach power domain \"%s\"\n", data->gpc_name); - ret = PTR_ERR(domain->power_dev); goto cleanup_pds; } diff --git a/drivers/pmdomain/imx/imx8mp-blk-ctrl.c b/drivers/pmdomain/imx/imx8mp-blk-ctrl.c index e3203eb6a022..77e889165eed 100644 --- a/drivers/pmdomain/imx/imx8mp-blk-ctrl.c +++ b/drivers/pmdomain/imx/imx8mp-blk-ctrl.c @@ -55,7 +55,7 @@ struct imx8mp_blk_ctrl_domain_data { const char *gpc_name; }; -#define DOMAIN_MAX_CLKS 2 +#define DOMAIN_MAX_CLKS 3 #define DOMAIN_MAX_PATHS 3 struct imx8mp_blk_ctrl_domain { @@ -457,8 +457,8 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = { }, [IMX8MP_HDMIBLK_PD_LCDIF] = { .name = "hdmiblk-lcdif", - .clk_names = (const char *[]){ "axi", "apb" }, - .num_clks = 2, + .clk_names = (const char *[]){ "axi", "apb", "fdcc" }, + .num_clks = 3, .gpc_name = "lcdif", .path_names = (const char *[]){"lcdif-hdmi"}, .num_paths = 1, @@ -483,8 +483,8 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = { }, [IMX8MP_HDMIBLK_PD_HDMI_TX] = { .name = "hdmiblk-hdmi-tx", - .clk_names = (const char *[]){ "apb", "ref_266m" }, - .num_clks = 2, + .clk_names = (const char *[]){ "apb", "ref_266m", "fdcc" }, + .num_clks = 3, .gpc_name = "hdmi-tx", }, [IMX8MP_HDMIBLK_PD_HDMI_TX_PHY] = { @@ -687,11 +687,14 @@ static int imx8mp_blk_ctrl_probe(struct platform_device *pdev) domain->power_dev = dev_pm_domain_attach_by_name(dev, data->gpc_name); - if (IS_ERR(domain->power_dev)) { - dev_err_probe(dev, PTR_ERR(domain->power_dev), + if (IS_ERR_OR_NULL(domain->power_dev)) { + if (!domain->power_dev) + ret = -ENODEV; + else + ret = PTR_ERR(domain->power_dev); + dev_err_probe(dev, ret, "failed to attach power domain %s\n", data->gpc_name); - ret = PTR_ERR(domain->power_dev); goto cleanup_pds; } diff --git a/drivers/pmdomain/imx/scu-pd.c b/drivers/pmdomain/imx/scu-pd.c index 891c1d925a9d..05841b0bf7f3 100644 --- a/drivers/pmdomain/imx/scu-pd.c +++ b/drivers/pmdomain/imx/scu-pd.c @@ -393,7 +393,7 @@ static int imx_sc_pd_power_off(struct generic_pm_domain *domain) return imx_sc_pd_power(domain, false); } -static struct generic_pm_domain *imx_scu_pd_xlate(struct of_phandle_args *spec, +static struct generic_pm_domain *imx_scu_pd_xlate(const struct of_phandle_args *spec, void *data) { struct generic_pm_domain *domain = ERR_PTR(-ENOENT); diff --git a/drivers/pmdomain/mediatek/mtk-scpsys.c b/drivers/pmdomain/mediatek/mtk-scpsys.c index b374d01fdac7..59a7a8c261ed 100644 --- a/drivers/pmdomain/mediatek/mtk-scpsys.c +++ b/drivers/pmdomain/mediatek/mtk-scpsys.c @@ -425,7 +425,6 @@ static struct scp *init_scp(struct platform_device *pdev, bool bus_prot_reg_update) { struct genpd_onecell_data *pd_data; - struct resource *res; int i, j; struct scp *scp; struct clk *clk[CLK_MAX]; @@ -441,8 +440,7 @@ static struct scp *init_scp(struct platform_device *pdev, scp->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - scp->base = devm_ioremap_resource(&pdev->dev, res); + scp->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(scp->base)) return ERR_CAST(scp->base); diff --git a/drivers/pmdomain/qcom/rpmpd.c b/drivers/pmdomain/qcom/rpmpd.c index 7796d65f96e8..5e6280b4cf70 100644 --- a/drivers/pmdomain/qcom/rpmpd.c +++ b/drivers/pmdomain/qcom/rpmpd.c @@ -16,6 +16,8 @@ #define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd) +static struct qcom_smd_rpm *rpmpd_smd_rpm; + /* Resource types: * RPMPD_X is X encoded as a little-endian, lower-case, ASCII string */ #define RPMPD_SMPA 0x61706d73 @@ -54,7 +56,6 @@ struct rpmpd { bool enabled; const int res_type; const int res_id; - struct qcom_smd_rpm *rpm; unsigned int max_state; __le32 key; bool state_synced; @@ -226,7 +227,46 @@ static struct rpmpd cx_s3a_vfl = { .key = KEY_FLOOR_LEVEL, }; +static struct rpmpd cx_s2b_corner_ao; +static struct rpmpd cx_s2b_corner = { + .pd = { .name = "cx", }, + .peer = &cx_s2b_corner_ao, + .res_type = RPMPD_SMPB, + .res_id = 2, + .key = KEY_CORNER, +}; + +static struct rpmpd cx_s2b_corner_ao = { + .pd = { .name = "cx_ao", }, + .peer = &cx_s2b_corner, + .active_only = true, + .res_type = RPMPD_SMPB, + .res_id = 2, + .key = KEY_CORNER, +}; + +static struct rpmpd cx_s2b_vfc = { + .pd = { .name = "cx_vfc", }, + .res_type = RPMPD_SMPB, + .res_id = 2, + .key = KEY_FLOOR_CORNER, +}; + /* G(F)X */ +static struct rpmpd gfx_s7a_corner = { + .pd = { .name = "gfx", }, + .res_type = RPMPD_SMPA, + .res_id = 7, + .key = KEY_CORNER, +}; + +static struct rpmpd gfx_s7a_vfc = { + .pd = { .name = "gfx_vfc", }, + .res_type = RPMPD_SMPA, + .res_id = 7, + .key = KEY_FLOOR_CORNER, +}; + static struct rpmpd gfx_s2b_corner = { .pd = { .name = "gfx", }, .res_type = RPMPD_SMPB, @@ -241,6 +281,20 @@ static struct rpmpd gfx_s2b_vfc = { .key = KEY_FLOOR_CORNER, }; +static struct rpmpd gfx_s4b_corner = { + .pd = { .name = "gfx", }, + .res_type = RPMPD_SMPB, + .res_id = 4, + .key = KEY_CORNER, +}; + +static struct rpmpd gfx_s4b_vfc = { + .pd = { .name = "gfx_vfc", }, + .res_type = RPMPD_SMPB, + .res_id = 4, + .key = KEY_FLOOR_CORNER, +}; + static struct rpmpd mx_rwmx0_lvl; static struct rpmpd gx_rwgx0_lvl_ao; static struct rpmpd gx_rwgx0_lvl = { @@ -663,6 +717,34 @@ static const struct rpmpd_desc msm8953_desc = { .max_state = RPM_SMD_LEVEL_TURBO, }; +static struct rpmpd *msm8974_rpmpds[] = { + [MSM8974_VDDCX] = &cx_s2b_corner, + [MSM8974_VDDCX_AO] = &cx_s2b_corner_ao, + [MSM8974_VDDCX_VFC] = &cx_s2b_vfc, + [MSM8974_VDDGFX] = &gfx_s4b_corner, + [MSM8974_VDDGFX_VFC] = &gfx_s4b_vfc, +}; + +static const struct rpmpd_desc msm8974_desc = { + .rpmpds = msm8974_rpmpds, + .num_pds = ARRAY_SIZE(msm8974_rpmpds), + .max_state = MAX_CORNER_RPMPD_STATE, +}; + +static struct rpmpd *msm8974pro_pma8084_rpmpds[] = { + [MSM8974_VDDCX] = &cx_s2a_corner, + [MSM8974_VDDCX_AO] = &cx_s2a_corner_ao, + [MSM8974_VDDCX_VFC] = &cx_s2a_vfc, + [MSM8974_VDDGFX] = &gfx_s7a_corner, + [MSM8974_VDDGFX_VFC] = &gfx_s7a_vfc, +}; + +static const struct rpmpd_desc msm8974pro_pma8084_desc = { + .rpmpds = msm8974pro_pma8084_rpmpds, + .num_pds = ARRAY_SIZE(msm8974pro_pma8084_rpmpds), + .max_state = MAX_CORNER_RPMPD_STATE, +}; + static struct rpmpd *msm8976_rpmpds[] = { [MSM8976_VDDCX] = &cx_s2a_lvl, [MSM8976_VDDCX_AO] = &cx_s2a_lvl_ao, @@ -856,6 +938,8 @@ static const struct of_device_id rpmpd_match_table[] = { { .compatible = "qcom,msm8917-rpmpd", .data = &msm8917_desc }, { .compatible = "qcom,msm8939-rpmpd", .data = &msm8939_desc }, { .compatible = "qcom,msm8953-rpmpd", .data = &msm8953_desc }, + { .compatible = "qcom,msm8974-rpmpd", .data = &msm8974_desc }, + { .compatible = "qcom,msm8974pro-pma8084-rpmpd", .data = &msm8974pro_pma8084_desc }, { .compatible = "qcom,msm8976-rpmpd", .data = &msm8976_desc }, { .compatible = "qcom,msm8994-rpmpd", .data = &msm8994_desc }, { .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc }, @@ -879,7 +963,7 @@ static int rpmpd_send_enable(struct rpmpd *pd, bool enable) .value = cpu_to_le32(enable), }; - return qcom_rpm_smd_write(pd->rpm, QCOM_SMD_RPM_ACTIVE_STATE, + return qcom_rpm_smd_write(rpmpd_smd_rpm, QCOM_SMD_RPM_ACTIVE_STATE, pd->res_type, pd->res_id, &req, sizeof(req)); } @@ -891,7 +975,7 @@ static int rpmpd_send_corner(struct rpmpd *pd, int state, unsigned int corner) .value = cpu_to_le32(corner), }; - return qcom_rpm_smd_write(pd->rpm, state, pd->res_type, pd->res_id, + return qcom_rpm_smd_write(rpmpd_smd_rpm, state, pd->res_type, pd->res_id, &req, sizeof(req)); }; @@ -1004,12 +1088,11 @@ static int rpmpd_probe(struct platform_device *pdev) int i; size_t num; struct genpd_onecell_data *data; - struct qcom_smd_rpm *rpm; struct rpmpd **rpmpds; const struct rpmpd_desc *desc; - rpm = dev_get_drvdata(pdev->dev.parent); - if (!rpm) { + rpmpd_smd_rpm = dev_get_drvdata(pdev->dev.parent); + if (!rpmpd_smd_rpm) { dev_err(&pdev->dev, "Unable to retrieve handle to RPM\n"); return -ENODEV; } @@ -1039,7 +1122,6 @@ static int rpmpd_probe(struct platform_device *pdev) continue; } - rpmpds[i]->rpm = rpm; rpmpds[i]->max_state = desc->max_state; rpmpds[i]->pd.power_off = rpmpd_power_off; rpmpds[i]->pd.power_on = rpmpd_power_on; diff --git a/drivers/pmdomain/renesas/Kconfig b/drivers/pmdomain/renesas/Kconfig index 80bf2cf8b60e..54acb4b1ec7c 100644 --- a/drivers/pmdomain/renesas/Kconfig +++ b/drivers/pmdomain/renesas/Kconfig @@ -71,6 +71,10 @@ config SYSC_R8A779G0 bool "System Controller support for R-Car V4H" if COMPILE_TEST select SYSC_RCAR_GEN4 +config SYSC_R8A779H0 + bool "System Controller support for R-Car V4M" if COMPILE_TEST + select SYSC_RCAR_GEN4 + config SYSC_RMOBILE bool "System Controller support for R-Mobile" if COMPILE_TEST diff --git a/drivers/pmdomain/renesas/Makefile b/drivers/pmdomain/renesas/Makefile index e306e396fc8c..89180f19c23b 100644 --- a/drivers/pmdomain/renesas/Makefile +++ b/drivers/pmdomain/renesas/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_SYSC_R8A77995) += r8a77995-sysc.o obj-$(CONFIG_SYSC_R8A779A0) += r8a779a0-sysc.o obj-$(CONFIG_SYSC_R8A779F0) += r8a779f0-sysc.o obj-$(CONFIG_SYSC_R8A779G0) += r8a779g0-sysc.o +obj-$(CONFIG_SYSC_R8A779H0) += r8a779h0-sysc.o # Family obj-$(CONFIG_SYSC_RCAR) += rcar-sysc.o obj-$(CONFIG_SYSC_RCAR_GEN4) += rcar-gen4-sysc.o diff --git a/drivers/pmdomain/renesas/r8a779a0-sysc.c b/drivers/pmdomain/renesas/r8a779a0-sysc.c index 04f1bc322ae7..54cdf250f7c2 100644 --- a/drivers/pmdomain/renesas/r8a779a0-sysc.c +++ b/drivers/pmdomain/renesas/r8a779a0-sysc.c @@ -5,19 +5,7 @@ * Copyright (C) 2020 Renesas Electronics Corp. */ -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include #include diff --git a/drivers/pmdomain/renesas/r8a779f0-sysc.c b/drivers/pmdomain/renesas/r8a779f0-sysc.c index 5602aa6bd7ed..6ed13cd1cb24 100644 --- a/drivers/pmdomain/renesas/r8a779f0-sysc.c +++ b/drivers/pmdomain/renesas/r8a779f0-sysc.c @@ -5,19 +5,7 @@ * Copyright (C) 2021 Renesas Electronics Corp. */ -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include #include diff --git a/drivers/pmdomain/renesas/r8a779g0-sysc.c b/drivers/pmdomain/renesas/r8a779g0-sysc.c index b932eba1b804..249cf43af45b 100644 --- a/drivers/pmdomain/renesas/r8a779g0-sysc.c +++ b/drivers/pmdomain/renesas/r8a779g0-sysc.c @@ -5,19 +5,7 @@ * Copyright (C) 2022 Renesas Electronics Corp. */ -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include #include diff --git a/drivers/pmdomain/renesas/r8a779h0-sysc.c b/drivers/pmdomain/renesas/r8a779h0-sysc.c new file mode 100644 index 000000000000..e13372cb80ee --- /dev/null +++ b/drivers/pmdomain/renesas/r8a779h0-sysc.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car V4M System Controller + * + * Copyright (C) 2023 Renesas Electronics Corp + */ + +#include + +#include + +#include "rcar-gen4-sysc.h" + +static struct rcar_gen4_sysc_area r8a779h0_areas[] __initdata = { + { "always-on", R8A779H0_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "c4", R8A779H0_PD_C4, R8A779H0_PD_ALWAYS_ON }, + { "a2e0d0", R8A779H0_PD_A2E0D0, R8A779H0_PD_C4, PD_SCU }, + { "a1e0d0c0", R8A779H0_PD_A1E0D0C0, R8A779H0_PD_A2E0D0, PD_CPU_NOCR }, + { "a1e0d0c1", R8A779H0_PD_A1E0D0C1, R8A779H0_PD_A2E0D0, PD_CPU_NOCR }, + { "a1e0d0c2", R8A779H0_PD_A1E0D0C2, R8A779H0_PD_A2E0D0, PD_CPU_NOCR }, + { "a1e0d0c3", R8A779H0_PD_A1E0D0C3, R8A779H0_PD_A2E0D0, PD_CPU_NOCR }, + { "a3cr0", R8A779H0_PD_A3CR0, R8A779H0_PD_ALWAYS_ON, PD_CPU_NOCR }, + { "a3cr1", R8A779H0_PD_A3CR1, R8A779H0_PD_ALWAYS_ON, PD_CPU_NOCR }, + { "a3cr2", R8A779H0_PD_A3CR2, R8A779H0_PD_ALWAYS_ON, PD_CPU_NOCR }, + { "a33dga", R8A779H0_PD_A33DGA, R8A779H0_PD_C4 }, + { "a23dgb", R8A779H0_PD_A23DGB, R8A779H0_PD_A33DGA }, + { "a3vip0", R8A779H0_PD_A3VIP0, R8A779H0_PD_C4 }, + { "a3vip2", R8A779H0_PD_A3VIP2, R8A779H0_PD_C4 }, + { "a3dul", R8A779H0_PD_A3DUL, R8A779H0_PD_C4 }, + { "a3isp0", R8A779H0_PD_A3ISP0, R8A779H0_PD_C4 }, + { "a2cn0", R8A779H0_PD_A2CN0, R8A779H0_PD_C4 }, + { "a1cn0", R8A779H0_PD_A1CN0, R8A779H0_PD_A2CN0 }, + { "a1dsp0", R8A779H0_PD_A1DSP0, R8A779H0_PD_A2CN0 }, + { "a1dsp1", R8A779H0_PD_A1DSP1, R8A779H0_PD_A2CN0 }, + { "a2imp01", R8A779H0_PD_A2IMP01, R8A779H0_PD_C4 }, + { "a2psc", R8A779H0_PD_A2PSC, R8A779H0_PD_C4 }, + { "a2dma", R8A779H0_PD_A2DMA, R8A779H0_PD_C4 }, + { "a2cv0", R8A779H0_PD_A2CV0, R8A779H0_PD_C4 }, + { "a2cv1", R8A779H0_PD_A2CV1, R8A779H0_PD_C4 }, + { "a2cv2", R8A779H0_PD_A2CV2, R8A779H0_PD_C4 }, + { "a2cv3", R8A779H0_PD_A2CV3, R8A779H0_PD_C4 }, + { "a3imr0", R8A779H0_PD_A3IMR0, R8A779H0_PD_C4 }, + { "a3imr1", R8A779H0_PD_A3IMR1, R8A779H0_PD_C4 }, + { "a3imr2", R8A779H0_PD_A3IMR2, R8A779H0_PD_C4 }, + { "a3imr3", R8A779H0_PD_A3IMR3, R8A779H0_PD_C4 }, + { "a3vc", R8A779H0_PD_A3VC, R8A779H0_PD_C4 }, + { "a3pci", R8A779H0_PD_A3PCI, R8A779H0_PD_C4 }, + { "a2pciphy", R8A779H0_PD_A2PCIPHY, R8A779H0_PD_A3PCI }, +}; + +const struct rcar_gen4_sysc_info r8a779h0_sysc_info __initconst = { + .areas = r8a779h0_areas, + .num_areas = ARRAY_SIZE(r8a779h0_areas), +}; diff --git a/drivers/pmdomain/renesas/rcar-gen4-sysc.c b/drivers/pmdomain/renesas/rcar-gen4-sysc.c index 9e5e6e077abc..66409cff2083 100644 --- a/drivers/pmdomain/renesas/rcar-gen4-sysc.c +++ b/drivers/pmdomain/renesas/rcar-gen4-sysc.c @@ -50,13 +50,13 @@ #define SYSCSR_BUSY GENMASK(1, 0) /* All bit sets is not busy */ #define SYSCSR_TIMEOUT 10000 -#define SYSCSR_DELAY_US 10 +#define SYSCSR_DELAY_US 1 -#define PDRESR_RETRIES 1000 -#define PDRESR_DELAY_US 10 +#define PDRESR_RETRIES 10000 +#define PDRESR_DELAY_US 1 -#define SYSCISR_TIMEOUT 10000 -#define SYSCISR_DELAY_US 10 +#define SYSCISCR_TIMEOUT 10000 +#define SYSCISCR_DELAY_US 1 #define RCAR_GEN4_PD_ALWAYS_ON 64 #define NUM_DOMAINS_EACH_REG BITS_PER_TYPE(u32) @@ -97,7 +97,7 @@ static int clear_irq_flags(unsigned int reg_idx, unsigned int isr_mask) ret = readl_poll_timeout_atomic(rcar_gen4_sysc_base + SYSCISCR(reg_idx), val, !(val & isr_mask), - SYSCISR_DELAY_US, SYSCISR_TIMEOUT); + SYSCISCR_DELAY_US, SYSCISCR_TIMEOUT); if (ret < 0) { pr_err("\n %s : Can not clear IRQ flags in SYSCISCR", __func__); return -EIO; @@ -157,7 +157,7 @@ static int rcar_gen4_sysc_power(u8 pdr, bool on) /* Wait until the power shutoff or resume request has completed * */ ret = readl_poll_timeout_atomic(rcar_gen4_sysc_base + SYSCISCR(reg_idx), val, (val & isr_mask), - SYSCISR_DELAY_US, SYSCISR_TIMEOUT); + SYSCISCR_DELAY_US, SYSCISCR_TIMEOUT); if (ret < 0) { ret = -EIO; goto out; @@ -284,6 +284,9 @@ static const struct of_device_id rcar_gen4_sysc_matches[] __initconst = { #endif #ifdef CONFIG_SYSC_R8A779G0 { .compatible = "renesas,r8a779g0-sysc", .data = &r8a779g0_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A779H0 + { .compatible = "renesas,r8a779h0-sysc", .data = &r8a779h0_sysc_info }, #endif { /* sentinel */ } }; diff --git a/drivers/pmdomain/renesas/rcar-gen4-sysc.h b/drivers/pmdomain/renesas/rcar-gen4-sysc.h index 388cfa8f8f9f..fdf843aa5113 100644 --- a/drivers/pmdomain/renesas/rcar-gen4-sysc.h +++ b/drivers/pmdomain/renesas/rcar-gen4-sysc.h @@ -40,5 +40,6 @@ struct rcar_gen4_sysc_info { extern const struct rcar_gen4_sysc_info r8a779a0_sysc_info; extern const struct rcar_gen4_sysc_info r8a779f0_sysc_info; extern const struct rcar_gen4_sysc_info r8a779g0_sysc_info; +extern const struct rcar_gen4_sysc_info r8a779h0_sysc_info; #endif /* __SOC_RENESAS_RCAR_GEN4_SYSC_H__ */ diff --git a/drivers/pmdomain/renesas/rcar-sysc.c b/drivers/pmdomain/renesas/rcar-sysc.c index eed47696e825..35d9aa0dfab8 100644 --- a/drivers/pmdomain/renesas/rcar-sysc.c +++ b/drivers/pmdomain/renesas/rcar-sysc.c @@ -45,10 +45,10 @@ #define PWRER_OFFS 0x14 /* Power Shutoff/Resume Error */ -#define SYSCSR_TIMEOUT 100 +#define SYSCSR_TIMEOUT 1000 #define SYSCSR_DELAY_US 1 -#define PWRER_RETRIES 100 +#define PWRER_RETRIES 1000 #define PWRER_DELAY_US 1 #define SYSCISR_TIMEOUT 1000 diff --git a/drivers/pmdomain/tegra/powergate-bpmp.c b/drivers/pmdomain/tegra/powergate-bpmp.c index 179ed895c279..b0138ca9f851 100644 --- a/drivers/pmdomain/tegra/powergate-bpmp.c +++ b/drivers/pmdomain/tegra/powergate-bpmp.c @@ -305,7 +305,7 @@ static void tegra_bpmp_remove_powergates(struct tegra_bpmp *bpmp) } static struct generic_pm_domain * -tegra_powergate_xlate(struct of_phandle_args *spec, void *data) +tegra_powergate_xlate(const struct of_phandle_args *spec, void *data) { struct generic_pm_domain *domain = ERR_PTR(-ENOENT); struct genpd_onecell_data *genpd = data; diff --git a/drivers/pmdomain/ti/omap_prm.c b/drivers/pmdomain/ti/omap_prm.c index c2feae3a634c..b8ceb3c2b81c 100644 --- a/drivers/pmdomain/ti/omap_prm.c +++ b/drivers/pmdomain/ti/omap_prm.c @@ -695,6 +695,8 @@ static int omap_prm_domain_init(struct device *dev, struct omap_prm *prm) data = prm->data; name = devm_kasprintf(dev, GFP_KERNEL, "prm_%s", data->name); + if (!name) + return -ENOMEM; prmd->dev = dev; prmd->prm = prm; diff --git a/drivers/pmdomain/ti/ti_sci_pm_domains.c b/drivers/pmdomain/ti/ti_sci_pm_domains.c index c091d569ecd5..9dddf227a3a6 100644 --- a/drivers/pmdomain/ti/ti_sci_pm_domains.c +++ b/drivers/pmdomain/ti/ti_sci_pm_domains.c @@ -85,7 +85,7 @@ static int ti_sci_pd_power_on(struct generic_pm_domain *domain) * @data: genpd core data for all the powerdomains on the device */ static struct generic_pm_domain *ti_sci_pd_xlate( - struct of_phandle_args *genpdspec, + const struct of_phandle_args *genpdspec, void *data) { struct genpd_onecell_data *genpd_data = data; diff --git a/drivers/pmdomain/xilinx/zynqmp-pm-domains.c b/drivers/pmdomain/xilinx/zynqmp-pm-domains.c index 6fd514286d82..0b5831e5ba1b 100644 --- a/drivers/pmdomain/xilinx/zynqmp-pm-domains.c +++ b/drivers/pmdomain/xilinx/zynqmp-pm-domains.c @@ -210,7 +210,7 @@ static void zynqmp_gpd_detach_dev(struct generic_pm_domain *domain, } static struct generic_pm_domain *zynqmp_gpd_xlate - (struct of_phandle_args *genpdspec, void *data) + (const struct of_phandle_args *genpdspec, void *data) { struct genpd_onecell_data *genpd_data = data; unsigned int i, idx = genpdspec->args[0]; diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c index a1c62d15f16c..d73727a5828a 100644 --- a/drivers/remoteproc/imx_dsp_rproc.c +++ b/drivers/remoteproc/imx_dsp_rproc.c @@ -103,12 +103,10 @@ enum imx_dsp_rp_mbox_messages { * @tx_ch: mailbox tx channel handle * @rx_ch: mailbox rx channel handle * @rxdb_ch: mailbox rx doorbell channel handle - * @pd_dev: power domain device - * @pd_dev_link: power domain device link + * @pd_list: power domain list * @ipc_handle: System Control Unit ipc handle * @rproc_work: work for processing virtio interrupts * @pm_comp: completion primitive to sync for suspend response - * @num_domains: power domain number * @flags: control flags */ struct imx_dsp_rproc { @@ -121,12 +119,10 @@ struct imx_dsp_rproc { struct mbox_chan *tx_ch; struct mbox_chan *rx_ch; struct mbox_chan *rxdb_ch; - struct device **pd_dev; - struct device_link **pd_dev_link; + struct dev_pm_domain_list *pd_list; struct imx_sc_ipc *ipc_handle; struct work_struct rproc_work; struct completion pm_comp; - int num_domains; u32 flags; }; @@ -955,74 +951,14 @@ static const struct rproc_ops imx_dsp_rproc_ops = { static int imx_dsp_attach_pm_domains(struct imx_dsp_rproc *priv) { struct device *dev = priv->rproc->dev.parent; - int ret, i; + int ret; - priv->num_domains = of_count_phandle_with_args(dev->of_node, - "power-domains", - "#power-domain-cells"); - - /* If only one domain, then no need to link the device */ - if (priv->num_domains <= 1) + /* A single PM domain is already attached. */ + if (dev->pm_domain) return 0; - priv->pd_dev = devm_kmalloc_array(dev, priv->num_domains, - sizeof(*priv->pd_dev), - GFP_KERNEL); - if (!priv->pd_dev) - return -ENOMEM; - - priv->pd_dev_link = devm_kmalloc_array(dev, priv->num_domains, - sizeof(*priv->pd_dev_link), - GFP_KERNEL); - if (!priv->pd_dev_link) - return -ENOMEM; - - for (i = 0; i < priv->num_domains; i++) { - priv->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i); - if (IS_ERR(priv->pd_dev[i])) { - ret = PTR_ERR(priv->pd_dev[i]); - goto detach_pm; - } - - /* - * device_link_add will check priv->pd_dev[i], if it is - * NULL, then will break. - */ - priv->pd_dev_link[i] = device_link_add(dev, - priv->pd_dev[i], - DL_FLAG_STATELESS | - DL_FLAG_PM_RUNTIME); - if (!priv->pd_dev_link[i]) { - dev_pm_domain_detach(priv->pd_dev[i], false); - ret = -EINVAL; - goto detach_pm; - } - } - - return 0; - -detach_pm: - while (--i >= 0) { - device_link_del(priv->pd_dev_link[i]); - dev_pm_domain_detach(priv->pd_dev[i], false); - } - - return ret; -} - -static int imx_dsp_detach_pm_domains(struct imx_dsp_rproc *priv) -{ - int i; - - if (priv->num_domains <= 1) - return 0; - - for (i = 0; i < priv->num_domains; i++) { - device_link_del(priv->pd_dev_link[i]); - dev_pm_domain_detach(priv->pd_dev[i], false); - } - - return 0; + ret = dev_pm_domain_attach_list(dev, NULL, &priv->pd_list); + return ret < 0 ? ret : 0; } /** @@ -1154,7 +1090,7 @@ static int imx_dsp_rproc_probe(struct platform_device *pdev) return 0; err_detach_domains: - imx_dsp_detach_pm_domains(priv); + dev_pm_domain_detach_list(priv->pd_list); err_put_rproc: rproc_free(rproc); @@ -1168,7 +1104,7 @@ static void imx_dsp_rproc_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); rproc_del(rproc); - imx_dsp_detach_pm_domains(priv); + dev_pm_domain_detach_list(priv->pd_list); rproc_free(rproc); } diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 8bb293b9f327..3161f14442bc 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -92,7 +92,6 @@ struct imx_rproc_mem { static int imx_rproc_xtr_mbox_init(struct rproc *rproc); static void imx_rproc_free_mbox(struct rproc *rproc); -static int imx_rproc_detach_pd(struct rproc *rproc); struct imx_rproc { struct device *dev; @@ -113,10 +112,8 @@ struct imx_rproc { u32 rproc_pt; /* partition id */ u32 rsrc_id; /* resource id */ u32 entry; /* cpu start address */ - int num_pd; u32 core_index; - struct device **pd_dev; - struct device_link **pd_dev_link; + struct dev_pm_domain_list *pd_list; }; static const struct imx_rproc_att imx_rproc_att_imx93[] = { @@ -853,7 +850,7 @@ static void imx_rproc_put_scu(struct rproc *rproc) return; if (imx_sc_rm_is_resource_owned(priv->ipc_handle, priv->rsrc_id)) { - imx_rproc_detach_pd(rproc); + dev_pm_domain_detach_list(priv->pd_list); return; } @@ -880,72 +877,20 @@ static int imx_rproc_partition_notify(struct notifier_block *nb, static int imx_rproc_attach_pd(struct imx_rproc *priv) { struct device *dev = priv->dev; - int ret, i; + int ret; + struct dev_pm_domain_attach_data pd_data = { + .pd_flags = PD_FLAG_DEV_LINK_ON, + }; /* * If there is only one power-domain entry, the platform driver framework * will handle it, no need handle it in this driver. */ - priv->num_pd = of_count_phandle_with_args(dev->of_node, "power-domains", - "#power-domain-cells"); - if (priv->num_pd <= 1) + if (dev->pm_domain) return 0; - priv->pd_dev = devm_kmalloc_array(dev, priv->num_pd, sizeof(*priv->pd_dev), GFP_KERNEL); - if (!priv->pd_dev) - return -ENOMEM; - - priv->pd_dev_link = devm_kmalloc_array(dev, priv->num_pd, sizeof(*priv->pd_dev_link), - GFP_KERNEL); - - if (!priv->pd_dev_link) - return -ENOMEM; - - for (i = 0; i < priv->num_pd; i++) { - priv->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i); - if (IS_ERR(priv->pd_dev[i])) { - ret = PTR_ERR(priv->pd_dev[i]); - goto detach_pd; - } - - priv->pd_dev_link[i] = device_link_add(dev, priv->pd_dev[i], DL_FLAG_STATELESS | - DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); - if (!priv->pd_dev_link[i]) { - dev_pm_domain_detach(priv->pd_dev[i], false); - ret = -EINVAL; - goto detach_pd; - } - } - - return 0; - -detach_pd: - while (--i >= 0) { - device_link_del(priv->pd_dev_link[i]); - dev_pm_domain_detach(priv->pd_dev[i], false); - } - - return ret; -} - -static int imx_rproc_detach_pd(struct rproc *rproc) -{ - struct imx_rproc *priv = rproc->priv; - int i; - - /* - * If there is only one power-domain entry, the platform driver framework - * will handle it, no need handle it in this driver. - */ - if (priv->num_pd <= 1) - return 0; - - for (i = 0; i < priv->num_pd; i++) { - device_link_del(priv->pd_dev_link[i]); - dev_pm_domain_detach(priv->pd_dev[i], false); - } - - return 0; + ret = dev_pm_domain_attach_list(dev, &pd_data, &priv->pd_list); + return ret < 0 ? ret : 0; } static int imx_rproc_detect_mode(struct imx_rproc *priv) diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c index 6c67514cc493..93f9a1537ec6 100644 --- a/drivers/remoteproc/qcom_q6v5_adsp.c +++ b/drivers/remoteproc/qcom_q6v5_adsp.c @@ -55,8 +55,6 @@ #define QDSP6SS_CORE_CBCR 0x20 #define QDSP6SS_SLEEP_CBCR 0x3c -#define QCOM_Q6V5_RPROC_PROXY_PD_MAX 3 - #define LPASS_BOOT_CORE_START BIT(0) #define LPASS_BOOT_CMD_START BIT(0) #define LPASS_EFUSE_Q6SS_EVB_SEL 0x0 @@ -74,7 +72,8 @@ struct adsp_pil_data { const char **clk_ids; int num_clks; - const char **proxy_pd_names; + const char **pd_names; + unsigned int num_pds; const char *load_state; }; @@ -110,8 +109,7 @@ struct qcom_adsp { size_t mem_size; bool has_iommu; - struct device *proxy_pds[QCOM_Q6V5_RPROC_PROXY_PD_MAX]; - size_t proxy_pd_count; + struct dev_pm_domain_list *pd_list; struct qcom_rproc_glink glink_subdev; struct qcom_rproc_ssr ssr_subdev; @@ -120,98 +118,92 @@ struct qcom_adsp { int (*shutdown)(struct qcom_adsp *adsp); }; -static int qcom_rproc_pds_attach(struct device *dev, struct qcom_adsp *adsp, - const char **pd_names) +static int qcom_rproc_pds_attach(struct qcom_adsp *adsp, const char **pd_names, + unsigned int num_pds) { - struct device **devs = adsp->proxy_pds; - size_t num_pds = 0; + struct device *dev = adsp->dev; + struct dev_pm_domain_attach_data pd_data = { + .pd_names = pd_names, + .num_pd_names = num_pds, + }; int ret; - int i; + + /* Handle single power domain */ + if (dev->pm_domain) + goto out; if (!pd_names) return 0; - /* Handle single power domain */ - if (dev->pm_domain) { - devs[0] = dev; - pm_runtime_enable(dev); - return 1; - } + ret = dev_pm_domain_attach_list(dev, &pd_data, &adsp->pd_list); + if (ret < 0) + return ret; - while (pd_names[num_pds]) - num_pds++; - - if (num_pds > ARRAY_SIZE(adsp->proxy_pds)) - return -E2BIG; - - for (i = 0; i < num_pds; i++) { - devs[i] = dev_pm_domain_attach_by_name(dev, pd_names[i]); - if (IS_ERR_OR_NULL(devs[i])) { - ret = PTR_ERR(devs[i]) ? : -ENODATA; - goto unroll_attach; - } - } - - return num_pds; - -unroll_attach: - for (i--; i >= 0; i--) - dev_pm_domain_detach(devs[i], false); - - return ret; +out: + pm_runtime_enable(dev); + return 0; } -static void qcom_rproc_pds_detach(struct qcom_adsp *adsp, struct device **pds, - size_t pd_count) +static void qcom_rproc_pds_detach(struct qcom_adsp *adsp) { struct device *dev = adsp->dev; - int i; + struct dev_pm_domain_list *pds = adsp->pd_list; - /* Handle single power domain */ - if (dev->pm_domain && pd_count) { - pm_runtime_disable(dev); - return; - } + dev_pm_domain_detach_list(pds); - for (i = 0; i < pd_count; i++) - dev_pm_domain_detach(pds[i], false); + if (dev->pm_domain || pds) + pm_runtime_disable(adsp->dev); } -static int qcom_rproc_pds_enable(struct qcom_adsp *adsp, struct device **pds, - size_t pd_count) +static int qcom_rproc_pds_enable(struct qcom_adsp *adsp) { - int ret; - int i; + struct device *dev = adsp->dev; + struct dev_pm_domain_list *pds = adsp->pd_list; + int ret, i = 0; - for (i = 0; i < pd_count; i++) { - dev_pm_genpd_set_performance_state(pds[i], INT_MAX); - ret = pm_runtime_resume_and_get(pds[i]); - if (ret < 0) { - dev_pm_genpd_set_performance_state(pds[i], 0); - goto unroll_pd_votes; - } + if (!dev->pm_domain && !pds) + return 0; + + if (dev->pm_domain) + dev_pm_genpd_set_performance_state(dev, INT_MAX); + + while (pds && i < pds->num_pds) { + dev_pm_genpd_set_performance_state(pds->pd_devs[i], INT_MAX); + i++; } - return 0; + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) { + while (pds && i > 0) { + i--; + dev_pm_genpd_set_performance_state(pds->pd_devs[i], 0); + } -unroll_pd_votes: - for (i--; i >= 0; i--) { - dev_pm_genpd_set_performance_state(pds[i], 0); - pm_runtime_put(pds[i]); + if (dev->pm_domain) + dev_pm_genpd_set_performance_state(dev, 0); } return ret; } -static void qcom_rproc_pds_disable(struct qcom_adsp *adsp, struct device **pds, - size_t pd_count) +static void qcom_rproc_pds_disable(struct qcom_adsp *adsp) { - int i; + struct device *dev = adsp->dev; + struct dev_pm_domain_list *pds = adsp->pd_list; + int i = 0; - for (i = 0; i < pd_count; i++) { - dev_pm_genpd_set_performance_state(pds[i], 0); - pm_runtime_put(pds[i]); + if (!dev->pm_domain && !pds) + return; + + if (dev->pm_domain) + dev_pm_genpd_set_performance_state(dev, 0); + + while (pds && i < pds->num_pds) { + dev_pm_genpd_set_performance_state(pds->pd_devs[i], 0); + i++; } + + pm_runtime_put(dev); } static int qcom_wpss_shutdown(struct qcom_adsp *adsp) @@ -397,8 +389,7 @@ static int adsp_start(struct rproc *rproc) if (ret) goto adsp_smmu_unmap; - ret = qcom_rproc_pds_enable(adsp, adsp->proxy_pds, - adsp->proxy_pd_count); + ret = qcom_rproc_pds_enable(adsp); if (ret < 0) goto disable_xo_clk; @@ -448,7 +439,7 @@ static int adsp_start(struct rproc *rproc) disable_adsp_clks: clk_bulk_disable_unprepare(adsp->num_clks, adsp->clks); disable_power_domain: - qcom_rproc_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count); + qcom_rproc_pds_disable(adsp); disable_xo_clk: clk_disable_unprepare(adsp->xo); adsp_smmu_unmap: @@ -464,7 +455,7 @@ static void qcom_adsp_pil_handover(struct qcom_q6v5 *q6v5) struct qcom_adsp *adsp = container_of(q6v5, struct qcom_adsp, q6v5); clk_disable_unprepare(adsp->xo); - qcom_rproc_pds_disable(adsp, adsp->proxy_pds, adsp->proxy_pd_count); + qcom_rproc_pds_disable(adsp); } static int adsp_stop(struct rproc *rproc) @@ -715,13 +706,11 @@ static int adsp_probe(struct platform_device *pdev) if (ret) goto free_rproc; - ret = qcom_rproc_pds_attach(adsp->dev, adsp, - desc->proxy_pd_names); + ret = qcom_rproc_pds_attach(adsp, desc->pd_names, desc->num_pds); if (ret < 0) { dev_err(&pdev->dev, "Failed to attach proxy power domains\n"); goto free_rproc; } - adsp->proxy_pd_count = ret; ret = adsp_init_reset(adsp); if (ret) @@ -753,7 +742,7 @@ static int adsp_probe(struct platform_device *pdev) return 0; disable_pm: - qcom_rproc_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count); + qcom_rproc_pds_detach(adsp); free_rproc: rproc_free(rproc); @@ -771,7 +760,7 @@ static void adsp_remove(struct platform_device *pdev) qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev); qcom_remove_sysmon_subdev(adsp->sysmon); qcom_remove_ssr_subdev(adsp->rproc, &adsp->ssr_subdev); - qcom_rproc_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count); + qcom_rproc_pds_detach(adsp); rproc_free(adsp->rproc); } @@ -788,9 +777,8 @@ static const struct adsp_pil_data adsp_resource_init = { "qdsp6ss_xo", "qdsp6ss_sleep", "qdsp6ss_core", NULL }, .num_clks = 7, - .proxy_pd_names = (const char*[]) { - "cx", NULL - }, + .pd_names = (const char*[]) { "cx" }, + .num_pds = 1, }; static const struct adsp_pil_data adsp_sc7280_resource_init = { @@ -821,9 +809,8 @@ static const struct adsp_pil_data cdsp_resource_init = { "q6_axim", NULL }, .num_clks = 7, - .proxy_pd_names = (const char*[]) { - "cx", NULL - }, + .pd_names = (const char*[]) { "cx" }, + .num_pds = 1, }; static const struct adsp_pil_data wpss_resource_init = { @@ -839,9 +826,8 @@ static const struct adsp_pil_data wpss_resource_init = { "ahb_bdg", "ahb", "rscp", NULL }, .num_clks = 3, - .proxy_pd_names = (const char*[]) { - "cx", "mx", NULL - }, + .pd_names = (const char*[]) { "cx", "mx" }, + .num_pds = 2, }; static const struct of_device_id adsp_of_match[] = { diff --git a/include/dt-bindings/power/qcom-rpmpd.h b/include/dt-bindings/power/qcom-rpmpd.h index 7f4e2983a4c5..608087fb9a3d 100644 --- a/include/dt-bindings/power/qcom-rpmpd.h +++ b/include/dt-bindings/power/qcom-rpmpd.h @@ -308,6 +308,13 @@ #define MSM8953_VDDMX 5 #define MSM8953_VDDMX_AO 6 +/* MSM8974 Power Domain Indexes */ +#define MSM8974_VDDCX 0 +#define MSM8974_VDDCX_AO 1 +#define MSM8974_VDDCX_VFC 2 +#define MSM8974_VDDGFX 3 +#define MSM8974_VDDGFX_VFC 4 + /* MSM8976 Power Domain Indexes */ #define MSM8976_VDDCX 0 #define MSM8976_VDDCX_AO 1 diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index b97c5e9820f9..772d3280d35f 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -19,6 +19,33 @@ #include #include +/* + * Flags to control the behaviour when attaching a device to its PM domains. + * + * PD_FLAG_NO_DEV_LINK: As the default behaviour creates a device-link + * for every PM domain that gets attached, this + * flag can be used to skip that. + * + * PD_FLAG_DEV_LINK_ON: Add the DL_FLAG_RPM_ACTIVE to power-on the + * supplier and its PM domain when creating the + * device-links. + * + */ +#define PD_FLAG_NO_DEV_LINK BIT(0) +#define PD_FLAG_DEV_LINK_ON BIT(1) + +struct dev_pm_domain_attach_data { + const char * const *pd_names; + const u32 num_pd_names; + const u32 pd_flags; +}; + +struct dev_pm_domain_list { + struct device **pd_devs; + struct device_link **pd_links; + u32 num_pds; +}; + /* * Flags to control the behaviour of a genpd. * @@ -322,7 +349,7 @@ static inline void dev_pm_genpd_resume(struct device *dev) {} /* OF PM domain providers */ struct of_device_id; -typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args, +typedef struct generic_pm_domain *(*genpd_xlate_t)(const struct of_phandle_args *args, void *data); struct genpd_onecell_data { @@ -337,11 +364,11 @@ int of_genpd_add_provider_simple(struct device_node *np, int of_genpd_add_provider_onecell(struct device_node *np, struct genpd_onecell_data *data); void of_genpd_del_provider(struct device_node *np); -int of_genpd_add_device(struct of_phandle_args *args, struct device *dev); -int of_genpd_add_subdomain(struct of_phandle_args *parent_spec, - struct of_phandle_args *subdomain_spec); -int of_genpd_remove_subdomain(struct of_phandle_args *parent_spec, - struct of_phandle_args *subdomain_spec); +int of_genpd_add_device(const struct of_phandle_args *args, struct device *dev); +int of_genpd_add_subdomain(const struct of_phandle_args *parent_spec, + const struct of_phandle_args *subdomain_spec); +int of_genpd_remove_subdomain(const struct of_phandle_args *parent_spec, + const struct of_phandle_args *subdomain_spec); struct generic_pm_domain *of_genpd_remove_last(struct device_node *np); int of_genpd_parse_idle_states(struct device_node *dn, struct genpd_power_state **states, int *n); @@ -366,20 +393,20 @@ static inline int of_genpd_add_provider_onecell(struct device_node *np, static inline void of_genpd_del_provider(struct device_node *np) {} -static inline int of_genpd_add_device(struct of_phandle_args *args, +static inline int of_genpd_add_device(const struct of_phandle_args *args, struct device *dev) { return -ENODEV; } -static inline int of_genpd_add_subdomain(struct of_phandle_args *parent_spec, - struct of_phandle_args *subdomain_spec) +static inline int of_genpd_add_subdomain(const struct of_phandle_args *parent_spec, + const struct of_phandle_args *subdomain_spec) { return -ENODEV; } -static inline int of_genpd_remove_subdomain(struct of_phandle_args *parent_spec, - struct of_phandle_args *subdomain_spec) +static inline int of_genpd_remove_subdomain(const struct of_phandle_args *parent_spec, + const struct of_phandle_args *subdomain_spec) { return -ENODEV; } @@ -420,7 +447,11 @@ struct device *dev_pm_domain_attach_by_id(struct device *dev, unsigned int index); struct device *dev_pm_domain_attach_by_name(struct device *dev, const char *name); +int dev_pm_domain_attach_list(struct device *dev, + const struct dev_pm_domain_attach_data *data, + struct dev_pm_domain_list **list); void dev_pm_domain_detach(struct device *dev, bool power_off); +void dev_pm_domain_detach_list(struct dev_pm_domain_list *list); int dev_pm_domain_start(struct device *dev); void dev_pm_domain_set(struct device *dev, struct dev_pm_domain *pd); int dev_pm_domain_set_performance_state(struct device *dev, unsigned int state); @@ -439,7 +470,14 @@ static inline struct device *dev_pm_domain_attach_by_name(struct device *dev, { return NULL; } +static inline int dev_pm_domain_attach_list(struct device *dev, + const struct dev_pm_domain_attach_data *data, + struct dev_pm_domain_list **list) +{ + return 0; +} static inline void dev_pm_domain_detach(struct device *dev, bool power_off) {} +static inline void dev_pm_domain_detach_list(struct dev_pm_domain_list *list) {} static inline int dev_pm_domain_start(struct device *dev) { return 0;