Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b30e8ff0 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: vidc: Add support for interframe power collapse"

parents 83530846 b4bc3f3e
Loading
Loading
Loading
Loading
+40 −22
Original line number Diff line number Diff line
@@ -12,7 +12,6 @@ Required properties:
Optional properties:
- reg : offset and length of the register set for the device.
- interrupts : should contain the vidc interrupt.
- vdd-supply : regulator to supply venus.
- qcom,vidc-cp-map : start and size of device virtual address range for
  secure buffers. Video hardware uses this address range to identify if
  the buffers are secure or non-secure.
@@ -60,6 +59,19 @@ Optional properties:
          internal persist = 0x80
          internal persist1 = 0x100
          internal cmd queue = 0x200
- *-supply: A phandle pointing to the appropriate regulator. Number of
  regulators vary across targets.
- qcom,clock-names: an array of clocks that the driver is supposed to be
  manipulating. The clocks names here correspond to the clock names used in
  clk_get(<name>).
- qcom,clock-configs = an array of bitmaps of clocks' configurations. The index
  of the bitmap corresponds to the clock at the same index in qcom,clock-names.
  The bitmaps describes the actions that the device needs to take regarding the
  clock (i.e. scale it based on load).

  The bitmap is defined as:
  scalable = 0x1 (if the driver should vary the clock's frequency based on load)
  power collapsible = 0x2 (if the driver should disable the clock if no load)

Example:

@@ -68,7 +80,9 @@ Example:
		compatible = "qcom,msm-vidc";
		reg = <0xfdc00000 0xff000>;
		interrupts = <0 44 0>;
		vdd-supply = <&gdsc_venus>;
		venus-supply = <&gdsc>;
		venus-core0-supply = <&gdsc1>;
		venus-core1-supply = <&gdsc2>;
		qcom,vidc-cp-map = <0x1000000 0x40000000>;
		qcom,vidc-ns-map = <0x40000000 0x40000000>;
		qcom,load-freq-tbl = <979200 410000000>,
@@ -106,4 +120,8 @@ Example:
							<0x1f1>;
			};
		};

		qcom,clock-names = "foo_clk", "bar_clk", "baz_clk";
		qcom,clock-properties = <0x3 0x1 0x0>;

	};
+19 −0
Original line number Diff line number Diff line
@@ -265,6 +265,25 @@ int create_pkt_cmd_session_cmd(struct vidc_hal_session_cmd_pkt *pkt,
	return rc;
}

int create_pkt_cmd_sys_power_control(
	struct hfi_cmd_sys_set_property_packet *pkt, u32 enable)
{
	struct hfi_enable *hfi;
	if (!pkt) {
		dprintk(VIDC_ERR, "No input packet\n");
		return -EINVAL;
	}

	pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
		sizeof(struct hfi_enable) + sizeof(u32);
	pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY;
	pkt->num_properties = 1;
	pkt->rg_property_data[0] = HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL;
	hfi = (struct hfi_enable *) &pkt->rg_property_data[1];
	hfi->enable = enable;
	return 0;
}

static u32 get_hfi_buffer(int hal_buffer)
{
	u32 buffer;
+3 −0
Original line number Diff line number Diff line
@@ -26,6 +26,9 @@ int create_pkt_cmd_sys_idle_indicator(
		struct hfi_cmd_sys_set_property_packet *pkt,
		u32 enable);

int create_pkt_cmd_sys_power_control(
	struct hfi_cmd_sys_set_property_packet *pkt, u32 enable);

int create_pkt_set_cmd_sys_resource(
		struct hfi_cmd_sys_set_resource_packet *pkt,
		struct vidc_resource_hdr *resource_hdr,
+213 −4
Original line number Diff line number Diff line
@@ -17,6 +17,11 @@
#include "msm_vidc_debug.h"
#include "msm_vidc_res_parse.h"

enum clock_properties {
	CLOCK_PROP_HAS_SCALING = 1 << 0,
	CLOCK_PROP_HAS_SW_POWER_COLLAPSE = 1 << 1,
};

struct master_slave {
	int masters_ocmem[2];
	int masters_ddr[2];
@@ -157,9 +162,36 @@ static inline void msm_vidc_free_buffer_usage_table(
	res->buffer_usage_set.buffer_usage_tbl = NULL;
}

static inline void msm_vidc_free_regulator_table(
			struct msm_vidc_platform_resources *res)
{
	int c = 0;
	for (c = 0; c < res->regulator_set.count; ++c) {
		struct regulator_info *rinfo =
			&res->regulator_set.regulator_tbl[c];

		kfree(rinfo->name);
		rinfo->name = NULL;
	}

	kfree(res->regulator_set.regulator_tbl);
	res->regulator_set.regulator_tbl = NULL;
	res->regulator_set.count = 0;
}

static inline void msm_vidc_free_clock_table(
			struct msm_vidc_platform_resources *res)
{
	kfree(res->clock_set.clock_tbl);
	res->clock_set.clock_tbl = NULL;
	res->clock_set.count = 0;
}

void msm_vidc_free_platform_resources(
			struct msm_vidc_platform_resources *res)
{
	msm_vidc_free_clock_table(res);
	msm_vidc_free_regulator_table(res);
	msm_vidc_free_freq_table(res);
	msm_vidc_free_reg_table(res);
	msm_vidc_free_bus_vectors(res);
@@ -480,7 +512,7 @@ static int msm_vidc_load_iommu_groups(struct msm_vidc_platform_resources *res)
			of_property_read_bool(ctx_node,	"qcom,secure-domain");

		dprintk(VIDC_DBG,
				"domain %s : secure = %d",
				"domain %s : secure = %d\n",
				iommu_map->name,
				iommu_map->is_secure);

@@ -492,7 +524,7 @@ static int msm_vidc_load_iommu_groups(struct msm_vidc_platform_resources *res)

		if (rc) {
			dprintk(VIDC_ERR,
					"cannot load partition buffertype information (%d)",
					"cannot load partition buffertype information (%d)\n",
					rc);
			rc = -ENOENT;
			goto err_load_groups;
@@ -546,6 +578,165 @@ err_load_buf_usage:
	return rc;
}

static int msm_vidc_load_regulator_table(
		struct msm_vidc_platform_resources *res)
{
	int rc = 0;
	struct platform_device *pdev = res->pdev;
	struct regulator_set *regulators = &res->regulator_set;
	struct device_node *domains_parent_node = NULL;
	struct property *domains_property = NULL;

	regulators->count = 0;
	regulators->regulator_tbl = NULL;

	domains_parent_node = pdev->dev.of_node;
	for_each_property_of_node(domains_parent_node, domains_property) {
		const char *search_string = "-supply";
		char *supply;
		bool matched = false;
		struct device_node *regulator_node = NULL;
		struct regulator_info *rinfo = NULL;
		void *temp = NULL;

		/* 1) check if current property is possibly a regulator */
		supply = strnstr(domains_property->name, search_string,
				strlen(domains_property->name) + 1);
		matched = supply && (*(supply + strlen(search_string)) == '\0');
		if (!matched)
			continue;

		/* 2) make sure prop isn't being misused */
		regulator_node = of_parse_phandle(domains_parent_node,
				domains_property->name, 0);
		if (IS_ERR(regulator_node)) {
			dprintk(VIDC_WARN, "%s is not a phandle\n",
					domains_property->name);
			continue;
		}

		/* 3) expand our table */
		temp = krealloc(regulators->regulator_tbl,
				sizeof(*regulators->regulator_tbl) *
				(regulators->count + 1), GFP_KERNEL);
		if (!temp) {
			rc = -ENOMEM;
			dprintk(VIDC_ERR,
					"Failed to alloc memory for regulator table\n");
			goto err_reg_tbl_alloc;
		}

		regulators->regulator_tbl = temp;
		regulators->count++;

		/* 4) populate regulator info */
		rinfo = &regulators->regulator_tbl[regulators->count - 1];
		rinfo->name = kstrndup(domains_property->name,
				supply - domains_property->name, GFP_KERNEL);
		if (!rinfo->name) {
			rc = -ENOMEM;
			dprintk(VIDC_ERR,
					"Failed to alloc memory for regulator name\n");
			goto err_reg_name_alloc;
		}

		rinfo->has_hw_power_collapse = of_property_read_bool(
			regulator_node, "qcom,support-hw-trigger");

		dprintk(VIDC_DBG, "Found regulator %s: h/w collapse = %s\n",
				rinfo->name,
				rinfo->has_hw_power_collapse ? "yes" : "no");
	}

	if (!regulators->count)
		dprintk(VIDC_DBG, "No regulators found");

	return 0;

err_reg_name_alloc:
err_reg_tbl_alloc:
	msm_vidc_free_regulator_table(res);
	return rc;
}

static int msm_vidc_load_clock_table(
		struct msm_vidc_platform_resources *res)
{
	int rc = 0, num_clocks = 0, c = 0;
	struct platform_device *pdev = res->pdev;
	int *clock_props = NULL;
	struct venus_clock_set *clocks = &res->clock_set;

	num_clocks = of_property_count_strings(pdev->dev.of_node,
				"qcom,clock-names");
	if (num_clocks <= 0) {
		/* Devices such as Q6 might not have any control over clocks
		 * hence have none specified, which is ok. */
		dprintk(VIDC_DBG, "No clocks found\n");
		clocks->count = 0;
		rc = 0;
		goto err_load_clk_table_fail;
	}

	clock_props = kzalloc(num_clocks * sizeof(*clock_props), GFP_KERNEL);
	if (!clock_props) {
		dprintk(VIDC_ERR, "No memory to read clock properties\n");
		rc = -ENOMEM;
		goto err_load_clk_table_fail;
	}

	rc = of_property_read_u32_array(pdev->dev.of_node,
				"qcom,clock-configs", clock_props,
				num_clocks);
	if (rc) {
		dprintk(VIDC_ERR, "Failed to read clock properties: %d\n", rc);
		goto err_load_clk_prop_fail;
	}

	clocks->clock_tbl = kzalloc(sizeof(*clocks->clock_tbl)
			* num_clocks, GFP_KERNEL);
	if (!clocks->clock_tbl) {
		dprintk(VIDC_ERR, "Failed to allocate memory for clock tbl\n");
		rc = -ENOMEM;
		goto err_load_clk_prop_fail;
	}

	clocks->count = num_clocks;
	dprintk(VIDC_DBG, "Found %d clocks\n", num_clocks);

	for (c = 0; c < num_clocks; ++c) {
		struct venus_clock *vc = &res->clock_set.clock_tbl[c];

		of_property_read_string_index(pdev->dev.of_node,
				"qcom,clock-names", c, &vc->name);

		if (clock_props[c] & CLOCK_PROP_HAS_SCALING) {
			vc->count = res->load_freq_tbl_size;
			vc->load_freq_tbl = res->load_freq_tbl;
		} else {
			vc->count = 0;
			vc->load_freq_tbl = NULL;
		}

		vc->has_sw_power_collapse = !!(clock_props[c] &
				CLOCK_PROP_HAS_SW_POWER_COLLAPSE);

		dprintk(VIDC_DBG,
				"Found clock %s: scales = %s, s/w collapse = %s\n",
				vc->name,
				vc->count ? "yes" : "no",
				vc->has_sw_power_collapse ? "yes" : "no");
	}

	kfree(clock_props);
	return 0;

err_load_clk_prop_fail:
	kfree(clock_props);
err_load_clk_table_fail:
	return rc;
}

int read_platform_resources_from_dt(
		struct msm_vidc_platform_resources *res)
{
@@ -597,16 +788,34 @@ int read_platform_resources_from_dt(
		goto err_load_buffer_usage_table;
	}

	rc = msm_vidc_load_regulator_table(res);
	if (rc) {
		dprintk(VIDC_ERR, "Failed to load list of regulators %d\n", rc);
		goto err_load_regulator_table;
	}

	rc = msm_vidc_load_clock_table(res);
	if (rc) {
		dprintk(VIDC_ERR,
			"Failed to load clock table: %d\n", rc);
		goto err_load_clock_table;
	}

	rc = of_property_read_u32(pdev->dev.of_node, "qcom,max-hw-load",
			&res->max_load);
	if (rc) {
		dprintk(VIDC_ERR,
			"Failed to determine max load supported: %d\n", rc);
		goto err_load_buffer_usage_table;
		goto err_load_max_hw_load;
	}

	return rc;

err_load_max_hw_load:
	msm_vidc_free_clock_table(res);
err_load_clock_table:
	msm_vidc_free_regulator_table(res);
err_load_regulator_table:
	msm_vidc_free_buffer_usage_table(res);
err_load_buffer_usage_table:
	msm_vidc_free_iommu_groups(res);
err_load_iommu_groups:
+26 −0
Original line number Diff line number Diff line
@@ -63,6 +63,30 @@ struct buffer_usage_set {
	u32 count;
};

struct regulator_info {
	struct regulator *regulator;
	bool has_hw_power_collapse;
	char *name;
};

struct regulator_set {
	struct regulator_info *regulator_tbl;
	u32 count;
};

struct venus_clock {
	const char *name;
	struct clk *clk;
	struct load_freq_table *load_freq_tbl;
	u32 count; /* == has_scaling iff count != 0 */
	bool has_sw_power_collapse;
};

struct venus_clock_set {
	struct venus_clock *clock_tbl;
	u32 count;
};

struct msm_vidc_platform_resources {
	uint32_t fw_base_addr;
	uint32_t register_base;
@@ -77,6 +101,8 @@ struct msm_vidc_platform_resources {
	uint32_t has_ocmem;
	uint32_t max_load;
	struct platform_device *pdev;
	struct regulator_set regulator_set;
	struct venus_clock_set clock_set;
};

static inline int is_iommu_present(struct msm_vidc_platform_resources *res)
Loading