Commit a070a08d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull pmdomain updates from Ulf Hansson:
 "Core:
   - Log a message when unused PM domains gets disabled
   - Scale down parent/child performance states in the reverse order

  Providers:
   - qcom: rpmpd: Add power domains support for MSM8974, MSM8974PRO,
     PMA8084 and PM8841
   - renesas: rcar-gen4-sysc: Reduce atomic delays
   - renesas: rcar-sysc: Adjust the waiting time to cover the worst case
   - renesas: r8a779h0-sysc: Add support for the r8a779h0 PM domains
   - imx: imx8mp-blk-ctrl: Add the fdcc clock to the hdmimix domains
   - imx: imx8mp-blk-ctrl: Error out if domains are missing in DT

  Improve support for multiple PM domains:
   - Add two helper functions to attach/detach multiple PM domains
   - Convert a couple of drivers to use the new helper functions"

* tag 'pmdomain-v6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm: (22 commits)
  pmdomain: renesas: rcar-gen4-sysc: Reduce atomic delays
  pmdomain: renesas: Adjust the waiting time to cover the worst case
  pmdomain: qcom: rpmpd: Add MSM8974PRO+PMA8084 power domains
  pmdomain: qcom: rpmpd: Add MSM8974+PM8841 power domains
  pmdomain: core: constify of_phandle_args in add device and subdomain
  pmdomain: core: constify of_phandle_args in xlate
  media: venus: Convert to dev_pm_domain_attach|detach_list() for vcodec
  remoteproc: qcom_q6v5_adsp: Convert to dev_pm_domain_attach|detach_list()
  remoteproc: imx_rproc: Convert to dev_pm_domain_attach|detach_list()
  remoteproc: imx_dsp_rproc: Convert to dev_pm_domain_attach|detach_list()
  PM: domains: Add helper functions to attach/detach multiple PM domains
  pmdomain: imx8mp-blk-ctrl: imx8mp_blk: Add fdcc clock to hdmimix domain
  pmdomain: mediatek: Use devm_platform_ioremap_resource() in init_scp()
  pmdomain: renesas: r8a779h0-sysc: Add r8a779h0 support
  pmdomain: imx8mp-blk-ctrl: Error out if domains are missing in DT
  pmdomain: ti: Add a null pointer check to the omap_prm_domain_init
  pmdomain: renesas: rcar-gen4-sysc: Remove unneeded includes
  pmdomain: core: Print a message when unused power domains are disabled
  pmdomain: qcom: rpmpd: Keep one RPM handle for all RPMPDs
  pmdomain: core: Scale down parent/child performance states in reverse order
  ...
parents 15223fdb ccabbb67
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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
+14 −8
Original line number Diff line number Diff line
@@ -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>;
    };
+134 −0
Original line number Diff line number Diff line
@@ -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.
+7 −5
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <media/videobuf2-v4l2.h>
#include <media/v4l2-mem2mem.h>
@@ -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,
+3 −4
Original line number Diff line number Diff line
@@ -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];
Loading