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

Commit 84f83672 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: modify bus table governor to add ubwc bus vectors"

parents 487b99ee 4ab27b02
Loading
Loading
Loading
Loading
+37 −13
Original line number Diff line number Diff line
@@ -3,23 +3,47 @@
Required properties:
- compatible : "qcom,msm-vidc,governor,table"
- name : name of the governor.
- qcom,bus-table : the table comprised of load (macro blocks per second),
  frequency (KBps) and codec type (u32) to select appropriate bus frequency
  for a given load and codec type.
- qcom,bus-table : node containing individual domain nodes, each with:
  - qcom,codec-mask: a bitmap of supported codec types, every two bits
    represents a codec type.
  - qcom,load-busfreq-tbl: load (in macroblocks/sec) and the corresponding
    bus frequency (in KBps) table.

Optional properties:
- qcom,low-power-mode: a boolean which indicates whether bus profile need
  to be used when client enables low-power mode.
- qcom,ubwc-mode: a boolean which indicates whether the bus profile need
  to be used when client enables UBWC mode.

Example:

venus-ddr-gov {
venus-bus-gov {
	compatible = "qcom,msm-vidc,governor,table";
	name = "qcom,venus-gov";
	qcom,bus-table =
		/* Encoders */
		<244800 787456 0x55555555>,   /* 1080p30E   */
		<108000 350208 0x55555555>,   /* 720p30E    */
		<0 0 0x55555555>,
		/* Decoders */
		<244800 618496 0xffffffff>,   /* 1080p30D   */
		<108000 314368 0xffffffff>,   /* 720p30D    */
		<0 0 0xffffffff>;
	qcom,bus-freq-table {
		qcom,profile-dec {
			qcom,codec-mask = <0xffffffff>;
			qcom,ubwc-mode;
			qcom,load-busfreq-tbl =
				<489600 1205248>,  /* 1080p60D   */
				<244800 618496>,   /* 1080p30D   */
				<216000 618496>,   /* 720p60D    */
				<108000 314368>,   /* 720p30D    */
				<72000  233472>,   /* VGA60D     */
				<36000  118784>,   /* VGA30D     */
				<0      0>;
		};
		qcom,profile-enc {
			qcom,codec-mask = <0x55555555>;
			qcom,low-power-mode;
			qcom,load-busfreq-tbl =
				<244800 787456>,   /* 1080p30E   */
				<216000 350208>,   /* 720p60E    */
				<108000 350208>,   /* 720p30E    */
				<72000  350208>,   /* VGA60E     */
				<36000  136806>,   /* VGA30E     */
				<0      0>;
		};
	};
};
+37 −30
Original line number Diff line number Diff line
/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -105,32 +105,39 @@
		compatible = "qcom,msm-vidc,governor,table";
		name = "venus-ddr-gov";
		status = "ok";
			qcom,bus-table =
				/* Encoders */
				<244800 698000 0x55555555>,   /* 1080p30E   */
				<216000 624000 0x55555555>,   /* 720p60E    */
				<194400 556000 0x55555555>,   /* FWVGA120E  */
				<144000 412000 0x55555555>,   /* VGA120E    */
				<108000 353000 0x55555555>,   /* 720p30E    */
				<97200  316000 0x55555555>,   /* FWVGA60E   */
				<48600  158000 0x55555555>,   /* FWVGA30E   */
				<72000  234000 0x55555555>,   /* VGA60E     */
				<36000  117000 0x55555555>,   /* VGA30E     */
				<18000  60000  0x55555555>,   /* QVGA60E    */
				<9000   30000  0x55555555>,   /* QVGA30E    */
				<0      0      0x55555555>,
				/* Decoders */
				<244800 605000 0xffffffff>,   /* 1080p30D   */
				<216000 540000 0xffffffff>,   /* 720p60D    */
				<194400 484000 0xffffffff>,   /* FWVGA120D  */
				<144000 360000 0xffffffff>,   /* VGA120D    */
				<108000 270000 0xffffffff>,   /* 720p30D    */
				<97200  242000 0xffffffff>,   /* FWVGA60D   */
				<48600  121000 0xffffffff>,   /* FWVGA30D   */
				<72000  180000 0xffffffff>,   /* VGA60D     */
				<36000  90000  0xffffffff>,   /* VGA30D     */
				<18000  45000  0xffffffff>,   /* HVGA30D    */
				<0      0      0xffffffff>;
		qcom,bus-freq-table {
			qcom,profile-enc {
				qcom,codec-mask = <0x55555555>;
				qcom,load-busfreq-tbl =
					<244800 698000>,   /* 1080p30E   */
					<216000 624000>,   /* 720p60E    */
					<194400 556000>,   /* FWVGA120E  */
					<144000 412000>,   /* VGA120E    */
					<108000 353000>,   /* 720p30E    */
					<97200  316000>,   /* FWVGA60E   */
					<48600  158000>,   /* FWVGA30E   */
					<72000  234000>,   /* VGA60E     */
					<36000  117000>,   /* VGA30E     */
					<18000  60000>,    /* QVGA60E    */
					<9000   30000>,    /* QVGA30E    */
					<0      0>;
			};
			qcom,profile-dec {
				qcom,codec-mask = <0xffffffff>;
				qcom,load-busfreq-tbl =
					<244800 605000>,   /* 1080p30D   */
					<216000 540000>,   /* 720p60D    */
					<194400 484000>,   /* FWVGA120D  */
					<144000 360000>,   /* VGA120D    */
					<108000 270000>,   /* 720p30D    */
					<97200  242000>,   /* FWVGA60D   */
					<48600  121000>,   /* FWVGA30D   */
					<72000  180000>,   /* VGA60D     */
					<36000  90000>,    /* VGA30D     */
					<18000  45000>,    /* HVGA30D    */
					<0      0>;
			};
		};
	};

};
+52 −4
Original line number Diff line number Diff line
/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -96,7 +96,7 @@
			label = "venus-ddr";
			qcom,bus-master = <63>;
			qcom,bus-slave = <512>;
			qcom,bus-governor = "msm-vidc-ddr";
			qcom,bus-governor = "venus-ddr-gov";
			qcom,bus-range-kbps = <1000 1205248>;
		};

@@ -109,4 +109,52 @@
			qcom,bus-range-kbps = <1 1>;
		};
	};

	venus-ddr-gov {
		compatible = "qcom,msm-vidc,governor,table";
		name = "venus-ddr-gov";
		status = "ok";
		qcom,bus-freq-table {
			qcom,profile-enc {
				qcom,codec-mask = <0x55555555>;
				qcom,load-busfreq-tbl =
					<979200 1044000>,  /* UHD30E     */
					<864000 887000>,   /* 720p240LPE */
					<489600 666000>,   /* 1080p60E   */
					<432000 578000>,   /* 720p120E   */
					<244800 346000>,   /* 1080p30E   */
					<216000 293000>,   /* 720p60E    */
					<108000 151000>,   /* 720p30E    */
					<0 0>;
			};
			qcom,profile-dec {
				qcom,codec-mask = <0xffffffff>;
				qcom,load-busfreq-tbl =
					<979200 2365000>,  /* UHD30D     */
					<979200 2241000>,  /* 1080p120D  */
					<864000 1978000>,  /* 720p240D   */
					<489600 1133000>,  /* 1080p60D   */
					<432000 994000>,   /* 720p120D   */
					<244800 580000>,   /* 1080p30D   */
					<216000 501000>,   /* 720p60E    */
					<108000 255000>,   /* 720p30D    */
					<0 0>;
			};
			qcom,profile-dec-ubwc {
				qcom,codec-mask = <0xffffffff>;
				qcom,ubwc-mode;
				qcom,load-busfreq-tbl =
					<979200 1892000>,  /* UHD30D     */
					<979200 1763000>,  /* 1080p120D  */
					<864000 1554000>,  /* 720p240D   */
					<489600 895000>,   /* 1080p60D   */
					<432000 781000>,   /* 720p120D   */
					<244800 460000>,   /* 1080p30D   */
					<216000 301000>,   /* 720p60E    */
					<108000 202000>,   /* 720p30D    */
					<0 0>;
			};
		};
	};

};
+194 −60
Original line number Diff line number Diff line
/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -16,74 +16,130 @@
#include <linux/string.h>
#include "governor.h"
#include "msm_vidc_debug.h"
#include "msm_vidc_res_parse.h"
#include "msm_vidc_internal.h"
#include "venus_hfi.h"

struct msm_vidc_bus_table_gov {
enum bus_profile {
	VIDC_BUS_PROFILE_NORMAL			= BIT(0),
	VIDC_BUS_PROFILE_LOW			= BIT(1),
	VIDC_BUS_PROFILE_UBWC			= BIT(2),
};

struct bus_profile_entry {
	struct {
		u32 load, freq, codecs;
		u32 load, freq;
	} *bus_table;
	int bus_table_size;
	u32 bus_table_size;
	u32 codec_mask;
	enum bus_profile profile;
};

struct msm_vidc_bus_table_gov {
	struct bus_profile_entry *bus_prof_entries;
	u32 count;
	struct devfreq_governor devfreq_gov;
};

int msm_vidc_table_get_target_freq(struct devfreq *dev, unsigned long *freq,
		u32 *flag)
static int __get_bus_freq(struct msm_vidc_bus_table_gov *gov,
		struct vidc_bus_vote_data *data,
		enum bus_profile profile)
{
	int i = 0, load = 0, freq = 0;
	enum vidc_vote_data_session sess_type = 0;
	struct bus_profile_entry *entry = NULL;
	bool found = false;

	load = NUM_MBS_PER_SEC(data->width, data->height, data->fps);
	sess_type = VIDC_VOTE_DATA_SESSION_VAL(data->codec, data->domain);

	/* check if ubwc bus profile is present */
	for (i = 0; i < gov->count; i++) {
		entry = &gov->bus_prof_entries[i];
		if (!entry->bus_table || !entry->bus_table_size)
			continue;
		if (!venus_hfi_is_session_supported(
				entry->codec_mask, sess_type))
			continue;
		if (entry->profile == profile) {
			found = true;
			break;
		}
	}

	if (found) {
		/* loop over bus table and select frequency */
		for (i = entry->bus_table_size - 1; i >= 0; --i) {
			/* load is arranged in descending order */
			freq = entry->bus_table[i].freq;
			if (load <= entry->bus_table[i].load)
				break;
		}
	}

	return freq;
}

static int msm_vidc_table_get_target_freq(struct devfreq *dev,
		unsigned long *frequency, u32 *flag)
{
	struct devfreq_dev_status status = {0};
	struct msm_vidc_gov_data *vidc_data = NULL;
	struct msm_vidc_bus_table_gov *gov = NULL;
	enum vidc_vote_data_session sess_type = 0;
	u32 load = 0, i = 0;
	int j = 0;
	enum bus_profile profile = 0;
	int i = 0;

	if (!dev || !freq || !flag) {
	if (!dev || !frequency || !flag) {
		dprintk(VIDC_ERR, "%s: Invalid params %p, %p, %p\n",
			__func__, dev, freq, flag);
			__func__, dev, frequency, flag);
		return -EINVAL;
	}

	gov = container_of(dev->governor,
			struct msm_vidc_bus_table_gov, devfreq_gov);
	if (!gov) {
		dprintk(VIDC_ERR, "%s: governor not found\n", __func__);
		return -EINVAL;
	}

	dev->profile->get_dev_status(dev->dev.parent, &status);
	vidc_data = (struct msm_vidc_gov_data *)status.private_data;

	*freq = 0;
	for (i = 0; i < vidc_data->data_count; ++i) {
		struct vidc_bus_vote_data *curr = &vidc_data->data[i];
		u32 frequency = 0;
	*frequency = 0;
	for (i = 0; i < vidc_data->data_count; i++) {
		struct vidc_bus_vote_data *data = &vidc_data->data[i];
		int freq = 0;

		load = NUM_MBS_PER_SEC(curr->width, curr->height, curr->fps);
		sess_type = VIDC_VOTE_DATA_SESSION_VAL(
			curr->codec, curr->domain);

		if (curr->power_mode == VIDC_POWER_TURBO) {
			dprintk(VIDC_DBG, "found turbo session[%d] %#x\n",
				i, sess_type);
			*freq = INT_MAX;
		if (data->power_mode == VIDC_POWER_TURBO) {
			dprintk(VIDC_DBG, "bus: found turbo session[%d] %#x\n",
				i, VIDC_VOTE_DATA_SESSION_VAL(data->codec,
					data->domain));
			*frequency = INT_MAX;
			goto exit;
		}

		profile = VIDC_BUS_PROFILE_NORMAL;
		if (data->color_formats[0] == HAL_COLOR_FORMAT_NV12_TP10_UBWC ||
			data->color_formats[0] == HAL_COLOR_FORMAT_NV12_UBWC)
			profile = VIDC_BUS_PROFILE_UBWC;

		freq = __get_bus_freq(gov, data, profile);
		/*
		 * loop over bus table and select frequency of
		 * matching session and appropriate load
		 * chose frequency from normal profile
		 * if specific profile frequency was not found.
		 */
		for (j = gov->bus_table_size - 1; j >= 0; --j) {
			bool matches = venus_hfi_is_session_supported(
					gov->bus_table[j].codecs, sess_type);
			if (!matches)
				continue;
		if (!freq)
			freq = __get_bus_freq(gov, data,
				VIDC_BUS_PROFILE_NORMAL);

			frequency = gov->bus_table[j].freq;
			if (load <= gov->bus_table[j].load)
				break;
		}
		*freq += frequency;
		*frequency += (unsigned long)freq;

		dprintk(VIDC_DBG,
			"session[%d] %#x, wxh %dx%d, fps %d, load %d, freq %d, total_freq %ld\n",
			i, sess_type, curr->width, curr->height,
			curr->fps, load, frequency, *freq);
			"session[%d] %#x: wxh %dx%d, fps %d, bus_profile %#x, freq %d, total_freq %ld KBps\n",
			i, VIDC_VOTE_DATA_SESSION_VAL(
			data->codec, data->domain), data->width,
			data->height, data->fps, profile,
			freq, *frequency);
	}
exit:
	return 0;
@@ -111,11 +167,34 @@ int msm_vidc_table_event_handler(struct devfreq *devfreq,
	return rc;
}

static int msm_vidc_free_bus_table(struct platform_device *pdev,
		struct msm_vidc_bus_table_gov *data)
{
	int rc = 0, i = 0;

	if (!pdev || !data) {
		dprintk(VIDC_ERR, "%s: invalid args %p %p\n",
			__func__, pdev, data);
		return -EINVAL;
	}

	for (i = 0; i < data->count; i++)
		data->bus_prof_entries[i].bus_table = NULL;

	data->bus_prof_entries = NULL;
	data->count = 0;

	return rc;
}

static int msm_vidc_load_bus_table(struct platform_device *pdev,
		struct msm_vidc_bus_table_gov *data)
{
	int c = 0;
	int rc = 0, i = 0, j = 0;
	const char *name = NULL;
	struct bus_profile_entry *entry = NULL;
	struct device_node *parent_node = NULL;
	struct device_node *child_node = NULL;

	if (!pdev || !data) {
		dprintk(VIDC_ERR, "%s: invalid args %p %p\n",
@@ -136,33 +215,84 @@ static int msm_vidc_load_bus_table(struct platform_device *pdev,
	data->devfreq_gov.get_target_freq = msm_vidc_table_get_target_freq;
	data->devfreq_gov.event_handler = msm_vidc_table_event_handler;

	data->bus_table_size = of_property_count_elems_of_size(
			pdev->dev.of_node, "qcom,bus-table",
			sizeof(*data->bus_table));
	if (data->bus_table_size <= 0) {
		dprintk(VIDC_ERR, "%s: invalid bus table size %d\n",
			__func__, data->bus_table_size);
		return -EINVAL;
	parent_node = of_find_node_by_name(pdev->dev.of_node,
			"qcom,bus-freq-table");
	if (!parent_node) {
		dprintk(VIDC_DBG, "Node qcom,bus-freq-table not found.\n");
		return 0;
	}

	data->bus_table = devm_kcalloc(&pdev->dev, data->bus_table_size,
			sizeof(*data->bus_table), GFP_KERNEL);
	if (!data->bus_table) {
		dprintk(VIDC_ERR, "%s: allocation failed\n", __func__);
	data->count = of_get_child_count(parent_node);
	if (!data->count) {
		dprintk(VIDC_DBG, "No child nodes in qcom,bus-freq-table\n");
		return 0;
	}

	data->bus_prof_entries = devm_kzalloc(&pdev->dev,
			sizeof(*data->bus_prof_entries) * data->count,
			GFP_KERNEL);
	if (!data->bus_prof_entries) {
		dprintk(VIDC_DBG, "no memory to allocate bus_prof_entries\n");
		return -ENOMEM;
	}

	of_property_read_u32_array(pdev->dev.of_node, "qcom,bus-table",
			(u32 *)data->bus_table,
			sizeof(*data->bus_table) /
			sizeof(u32) * data->bus_table_size);
	for_each_child_of_node(parent_node, child_node) {

		if (i >= data->count) {
			dprintk(VIDC_ERR,
				"qcom,bus-freq-table: invalid child node %d, max is %d\n",
				i, data->count);
			break;
		}
		entry = &data->bus_prof_entries[i];

		if (of_find_property(child_node, "qcom,codec-mask", NULL)) {
			rc = of_property_read_u32(child_node,
					"qcom,codec-mask", &entry->codec_mask);
			if (rc) {
				dprintk(VIDC_ERR,
					"qcom,codec-mask not found\n");
				break;
			}
		}

		if (of_find_property(child_node, "qcom,low-power-mode", NULL))
			entry->profile = VIDC_BUS_PROFILE_LOW;
		else if (of_find_property(child_node, "qcom,ubwc-mode", NULL))
			entry->profile = VIDC_BUS_PROFILE_UBWC;
		else
			entry->profile = VIDC_BUS_PROFILE_NORMAL;

		if (of_find_property(child_node,
					"qcom,load-busfreq-tbl", NULL)) {
			rc = msm_vidc_load_u32_table(pdev, child_node,
						"qcom,load-busfreq-tbl",
						sizeof(*entry->bus_table),
						(u32 **)&entry->bus_table,
						&entry->bus_table_size);
			if (rc) {
				dprintk(VIDC_ERR,
					"qcom,load-busfreq-tbl failed\n");
				break;
			}
		} else {
			entry->bus_table = NULL;
			entry->bus_table_size = 0;
		}

	dprintk(VIDC_DBG, "%s: bus table:\n", __func__);
	for (c = 0; c < data->bus_table_size; ++c)
		dprintk(VIDC_DBG, "%8d %8d %#x\n", data->bus_table[c].load,
			data->bus_table[c].freq, data->bus_table[c].codecs);
		dprintk(VIDC_DBG,
			"qcom,load-busfreq-tbl: size %d, codec_mask %#x, profile %#x\n",
			entry->bus_table_size, entry->codec_mask,
			entry->profile);
		for (j = 0; j < entry->bus_table_size; j++)
			dprintk(VIDC_DBG, "   load %8d freq %8d\n",
				entry->bus_table[j].load,
				entry->bus_table[j].freq);

		i++;
	}

	return 0;
	return rc;
}

static int msm_vidc_bus_table_probe(struct platform_device *pdev)
@@ -202,6 +332,10 @@ static int msm_vidc_bus_table_remove(struct platform_device *pdev)
	if (IS_ERR_OR_NULL(gov))
		return PTR_ERR(gov);

	rc = msm_vidc_free_bus_table(pdev, gov);
	if (rc)
		dprintk(VIDC_WARN, "%s: free bus table failed\n", __func__);

	rc = devfreq_remove_governor(&gov->devfreq_gov);

	return rc;
+18 −5
Original line number Diff line number Diff line
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -303,11 +303,24 @@ static int msm_vidc_load_imem_ab_table(struct msm_vidc_platform_resources *res)
	return 0;
}

/*
 * this is a generic implementation to load single or
 * multiple array table (array elements should be of u32)
/**
 * msm_vidc_load_u32_table() - load dtsi table entries
 * @pdev: A pointer to the platform device.
 * @of_node:      A pointer to the device node.
 * @table_name:   A pointer to the dtsi table entry name.
 * @struct_size:  The size of the structure which is nothing but
 *                a single entry in the dtsi table.
 * @table:        A pointer to the table pointer which needs to be
 *                filled by the dtsi table entries.
 * @num_elements: Number of elements pointer which needs to be filled
 *                with the number of elements in the table.
 *
 * This is a generic implementation to load single or multiple array
 * table from dtsi. The array elements should be of size equal to u32.
 *
 * Return:        Return '0' for success else appropriate error value.
 */
static int msm_vidc_load_u32_table(struct platform_device *pdev,
int msm_vidc_load_u32_table(struct platform_device *pdev,
		struct device_node *of_node, char *table_name, int struct_size,
		u32 **table, u32 *num_elements)
{
Loading