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

Commit 5fadccc7 authored by Vasantha Balla's avatar Vasantha Balla Committed by Gerrit - the friendly Code Review server
Browse files

vidc_3x: Use static table governor for bus voting



Current dynamic bus governor is not valid for sdm660/qm215.
so switching back to static table model.

Change-Id: If79af9913f637e544b3bb0bd10b9c0632d111825
Signed-off-by: default avatarVasantha Balla <vballa@codeaurora.org>
parent 65e986ff
Loading
Loading
Loading
Loading
+6 −268
Original line number Diff line number Diff line
@@ -24,27 +24,6 @@
#include "../vidc_hfi_api.h"


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;
	} *bus_table;
	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;
};

static int __get_bus_freq(struct msm_vidc_bus_table_gov *gov,
		struct vidc_bus_vote_data *data,
		enum bus_profile profile)
@@ -85,31 +64,19 @@ static int __get_bus_freq(struct msm_vidc_bus_table_gov *gov,
}


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

	if (!dev || !frequency) {
		dprintk(VIDC_ERR, "%s: Invalid params %pK, %pK\n",
			__func__, dev, frequency);
		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__);
	if (!frequency || !gov || !vidc_data)  {
		dprintk(VIDC_ERR, "%s: Invalid params %pK\n",
			__func__, frequency);
		return -EINVAL;
	}

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

	*frequency = 0;
	for (i = 0; i < vidc_data->data_count; i++) {
		struct vidc_bus_vote_data *data = &vidc_data->data[i];
@@ -149,232 +116,3 @@ static int msm_vidc_table_get_target_freq(struct devfreq *dev,
exit:
	return 0;
}

int msm_vidc_table_event_handler(struct devfreq *devfreq,
		unsigned int event, void *data)
{
	int rc = 0;

	if (!devfreq) {
		dprintk(VIDC_ERR, "%s: NULL devfreq\n", __func__);
		return -EINVAL;
	}

	switch (event) {
	case DEVFREQ_GOV_START:
	case DEVFREQ_GOV_RESUME:
		mutex_lock(&devfreq->lock);
		rc = update_devfreq(devfreq);
		mutex_unlock(&devfreq->lock);
		break;
	}

	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 %pK %pK\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 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 %pK %pK\n",
			__func__, pdev, data);
		return -EINVAL;
	}

	of_property_read_string(pdev->dev.of_node, "name", &name);
	if (strlen(name) > ARRAY_SIZE(data->devfreq_gov.name) - 1) {
		dprintk(VIDC_ERR,
			"%s: name is too long, max should be %zu chars\n",
			__func__, ARRAY_SIZE(data->devfreq_gov.name) - 1);
		return -EINVAL;
	}

	strlcpy((char *)data->devfreq_gov.name, name,
			ARRAY_SIZE(data->devfreq_gov.name));
	data->devfreq_gov.get_target_freq = msm_vidc_table_get_target_freq;
	data->devfreq_gov.event_handler = msm_vidc_table_event_handler;

	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->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;
	}

	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,
			"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 rc;
}

static int msm_vidc_bus_table_probe(struct platform_device *pdev)
{
	int rc = 0;
	struct msm_vidc_bus_table_gov *gov = NULL;

	dprintk(VIDC_DBG, "%s\n", __func__);

	gov = devm_kzalloc(&pdev->dev, sizeof(*gov), GFP_KERNEL);
	if (!gov) {
		dprintk(VIDC_ERR, "%s: allocation failed\n", __func__);
		return -ENOMEM;
	}

	platform_set_drvdata(pdev, gov);

	rc = msm_vidc_load_bus_table(pdev, gov);
	if (rc)
		return rc;

	rc = devfreq_add_governor(&gov->devfreq_gov);
	if (rc)
		dprintk(VIDC_ERR, "%s: add governor failed\n", __func__);

	return rc;
}

static int msm_vidc_bus_table_remove(struct platform_device *pdev)
{
	int rc = 0;
	struct msm_vidc_bus_table_gov *gov = NULL;

	dprintk(VIDC_DBG, "%s\n", __func__);

	gov = platform_get_drvdata(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;
}

static const struct of_device_id device_id[] = {
	{.compatible = "qcom,msm-vidc,governor,table"},
	{}
};

static struct platform_driver msm_vidc_bus_table_driver = {
	.probe = msm_vidc_bus_table_probe,
	.remove = msm_vidc_bus_table_remove,
	.driver = {
		.name = "msm_vidc_bus_table_governor",
		.of_match_table = device_id,
	},
};

static int __init msm_vidc_bus_table_init(void)
{

	dprintk(VIDC_DBG, "%s\n", __func__);

	return platform_driver_register(&msm_vidc_bus_table_driver);
}

module_init(msm_vidc_bus_table_init);

static void __exit msm_vidc_bus_table_exit(void)
{
	dprintk(VIDC_DBG, "%s\n", __func__);
	platform_driver_unregister(&msm_vidc_bus_table_driver);
}

module_exit(msm_vidc_bus_table_exit);
MODULE_LICENSE("GPL v2");
+127 −0
Original line number Diff line number Diff line
@@ -72,7 +72,23 @@ static inline enum imem_type read_imem_type(struct platform_device *pdev)
						IMEM_NONE;

}
static inline void msm_vidc_free_bus_table(
		struct msm_vidc_platform_resources *res)
{
	int i = 0;
	struct msm_vidc_bus_table_gov *data = res->gov_data;

	if (!data) {
		dprintk(VIDC_ERR, "%s: invalid args %pK\n",
			__func__, data);
	}

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

	data->bus_prof_entries = NULL;
	data->count = 0;
}
static inline void msm_vidc_free_allowed_clocks_table(
		struct msm_vidc_platform_resources *res)
{
@@ -174,6 +190,7 @@ void msm_vidc_free_platform_resources(
			struct msm_vidc_platform_resources *res)
{
	msm_vidc_free_clock_table(res);
	msm_vidc_free_bus_table(res);
	msm_vidc_free_regulator_table(res);
	msm_vidc_free_freq_table(res);
	msm_vidc_free_platform_version_table(res);
@@ -1065,7 +1082,108 @@ static int msm_vidc_load_clock_table(
err_load_clk_table_fail:
	return rc;
}
static int msm_vidc_load_bus_table(struct msm_vidc_platform_resources *res)
{
	int rc = 0, i = 0, j = 0;
	struct bus_profile_entry *entry = NULL;
	struct device_node *parent_node = NULL;
	struct device_node *child_node = NULL;
	struct msm_vidc_bus_table_gov *gov_data;
	struct platform_device *pdev = res->pdev;

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

	res->gov_data = devm_kzalloc(&pdev->dev, sizeof(*gov_data), GFP_KERNEL);
	if (!res->gov_data) {
		dprintk(VIDC_ERR, "%s: allocation failed\n", __func__);
		return -ENOMEM;
	}

	gov_data = res->gov_data;
	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;
	}

	gov_data->count = of_get_child_count(parent_node);
	if (!gov_data->count) {
		dprintk(VIDC_DBG, "No child nodes in qcom,bus-freq-table\n");
		return 0;
	}

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

	for_each_child_of_node(parent_node, child_node) {

		if (i >= gov_data->count) {
			dprintk(VIDC_ERR,
				"qcom,bus-freq-table: invalid child node %d, max is %d\n",
				i, gov_data->count);
			break;
		}
		entry = &gov_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,
			"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 rc;
}
int read_platform_resources_from_dt(
		struct msm_vidc_platform_resources *res)
{
@@ -1185,6 +1303,13 @@ int read_platform_resources_from_dt(
		goto err_load_allowed_clocks_table;
	}

	rc = msm_vidc_load_bus_table(res);
	if (rc) {
		dprintk(VIDC_ERR,
			"Failed to load bus table: %d\n", rc);
		goto err_load_bus_table;
	}

	rc = of_property_read_u32(pdev->dev.of_node, "qcom,max-hw-load",
			&res->max_load);
	if (rc) {
@@ -1236,6 +1361,8 @@ int read_platform_resources_from_dt(
err_setup_legacy_cb:
err_load_max_hw_load:
	msm_vidc_free_allowed_clocks_table(res);
err_load_bus_table:
	msm_vidc_free_bus_table(res);
err_load_allowed_clocks_table:
	msm_vidc_free_cycles_per_mb_table(res);
err_load_cycles_per_mb_table:
+22 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
 * Copyright (c) 2013-2021, 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
@@ -149,6 +149,26 @@ struct clock_freq_table {
	u32 count;
};

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;
	} *bus_table;
	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 msm_vidc_platform_resources {
	phys_addr_t firmware_base;
	phys_addr_t register_base;
@@ -176,6 +196,7 @@ struct msm_vidc_platform_resources {
	struct platform_device *pdev;
	struct regulator_set regulator_set;
	struct clock_set clock_set;
	struct msm_vidc_bus_table_gov *gov_data;
	struct bus_set bus_set;
	bool use_non_secure_pil;
	bool sw_power_collapsible;
+20 −6
Original line number Diff line number Diff line
@@ -113,7 +113,10 @@ static inline void __strict_check(struct venus_hfi_device *device)
		WARN_ON(VIDC_DBG_WARN_ENABLE);
	}
}

static inline bool is_clock_bus_voted(struct venus_hfi_device *device)
{
	return (device->bus_vote.total_bw_ddr && device->clk_freq);
}
static inline void __set_state(struct venus_hfi_device *device,
		enum venus_hfi_state state)
{
@@ -812,13 +815,18 @@ static int __vote_buses(struct venus_hfi_device *device,

	venus_hfi_for_each_bus(device, bus) {
		if (!bus->is_prfm_gov_used) {
			freq = __calc_bw(bus, &device->bus_vote);
			rc = __vote_bandwidth(bus, &freq);
		} else {
			freq = bus->range[1];
			rc = __vote_bandwidth(bus, &freq);
			rc = msm_vidc_table_get_target_freq(
					device->res->gov_data,
					&device->bus_vote, &freq);
			if (rc) {
				dprintk(VIDC_ERR, "unable to get freq\n");
				return rc;
			}
			device->bus_vote.total_bw_ddr = freq;
		} else
			freq = bus->range[1];

		rc = __vote_bandwidth(bus, &freq);
		if (rc)
			return rc;
	}
@@ -1527,6 +1535,12 @@ static int __iface_cmdq_write_relaxed(struct venus_hfi_device *device,
		goto err_q_write;
	}

	if (cmd_packet->packet_type == HFI_CMD_SESSION_EMPTY_BUFFER &&
				!is_clock_bus_voted(device))
		dprintk(VIDC_ERR, "%s: bus %llu bps or clock %lu MHz\n",
				__func__, device->bus_vote.total_bw_ddr,
					device->clk_freq);

	if (!__write_queue(q_info, (u8 *)pkt, requires_interrupt)) {
		if (device->res->sw_power_collapsible) {
			cancel_delayed_work(&venus_hfi_pm_work);
+4 −0
Original line number Diff line number Diff line
@@ -52,6 +52,10 @@

extern unsigned long __calc_bw(struct bus_info *bus,
				struct msm_vidc_gov_data *vidc_data);

extern int msm_vidc_table_get_target_freq(struct msm_vidc_bus_table_gov *gov,
					struct msm_vidc_gov_data *vidc_data,
					unsigned long *frequency);
struct hfi_queue_table_header {
	u32 qtbl_version;
	u32 qtbl_size;
Loading