Commit 32f0a6dd authored by Stanimir Varbanov's avatar Stanimir Varbanov Committed by Mauro Carvalho Chehab
Browse files

media: venus: Use on-chip interconnect API



This aims to add a requests for bandwidth scaling depending
on the resolution and framerate (macroblocks per second). The
exact value of the requested bandwidth is get from a
pre-calculated tables for encoder and decoder.

Acked-by: default avatarGeorgi Djakov <georgi.djakov@linaro.org>
Signed-off-by: default avatarStanimir Varbanov <stanimir.varbanov@linaro.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent c690435e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -483,6 +483,7 @@ config VIDEO_QCOM_VENUS
	tristate "Qualcomm Venus V4L2 encoder/decoder driver"
	depends on VIDEO_DEV && VIDEO_V4L2
	depends on (ARCH_QCOM && IOMMU_DMA) || COMPILE_TEST
	depends on INTERCONNECT || !INTERCONNECT
	select QCOM_MDT_LOADER if ARCH_QCOM
	select QCOM_SCM if ARCH_QCOM
	select VIDEOBUF2_DMA_SG
+34 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
 */
#include <linux/clk.h>
#include <linux/init.h>
#include <linux/interconnect.h>
#include <linux/ioctl.h>
#include <linux/list.h>
#include <linux/module.h>
@@ -239,6 +240,14 @@ static int venus_probe(struct platform_device *pdev)
	if (IS_ERR(core->base))
		return PTR_ERR(core->base);

	core->video_path = of_icc_get(dev, "video-mem");
	if (IS_ERR(core->video_path))
		return PTR_ERR(core->video_path);

	core->cpucfg_path = of_icc_get(dev, "cpu-cfg");
	if (IS_ERR(core->cpucfg_path))
		return PTR_ERR(core->cpucfg_path);

	core->irq = platform_get_irq(pdev, 0);
	if (core->irq < 0)
		return core->irq;
@@ -273,6 +282,10 @@ static int venus_probe(struct platform_device *pdev)
	if (ret)
		return ret;

	ret = icc_set_bw(core->cpucfg_path, 0, kbps_to_icc(1000));
	if (ret)
		return ret;

	ret = hfi_create(core, &venus_core_ops);
	if (ret)
		return ret;
@@ -355,6 +368,9 @@ static int venus_remove(struct platform_device *pdev)
	pm_runtime_put_sync(dev);
	pm_runtime_disable(dev);

	icc_put(core->video_path);
	icc_put(core->cpucfg_path);

	v4l2_device_unregister(&core->v4l2_dev);

	return ret;
@@ -465,9 +481,27 @@ static const struct freq_tbl sdm845_freq_table[] = {
	{  244800, 100000000 },	/* 1920x1080@30 */
};

static const struct bw_tbl sdm845_bw_table_enc[] = {
	{ 1944000, 1612000, 0, 2416000, 0 },	/* 3840x2160@60 */
	{  972000,  951000, 0, 1434000, 0 },	/* 3840x2160@30 */
	{  489600,  723000, 0,  973000, 0 },	/* 1920x1080@60 */
	{  244800,  370000, 0,	495000, 0 },	/* 1920x1080@30 */
};

static const struct bw_tbl sdm845_bw_table_dec[] = {
	{ 2073600, 3929000, 0, 5551000, 0 },	/* 4096x2160@60 */
	{ 1036800, 1987000, 0, 2797000, 0 },	/* 4096x2160@30 */
	{  489600, 1040000, 0, 1298000, 0 },	/* 1920x1080@60 */
	{  244800,  530000, 0,  659000, 0 },	/* 1920x1080@30 */
};

static const struct venus_resources sdm845_res = {
	.freq_tbl = sdm845_freq_table,
	.freq_tbl_size = ARRAY_SIZE(sdm845_freq_table),
	.bw_tbl_enc = sdm845_bw_table_enc,
	.bw_tbl_enc_size = ARRAY_SIZE(sdm845_bw_table_enc),
	.bw_tbl_dec = sdm845_bw_table_dec,
	.bw_tbl_dec_size = ARRAY_SIZE(sdm845_bw_table_dec),
	.clks = {"core", "iface", "bus" },
	.clks_num = 3,
	.max_load = 3110400,	/* 4096x2160@90 */
+14 −0
Original line number Diff line number Diff line
@@ -26,10 +26,22 @@ struct reg_val {
	u32 value;
};

struct bw_tbl {
	u32 mbs_per_sec;
	u32 avg;
	u32 peak;
	u32 avg_10bit;
	u32 peak_10bit;
};

struct venus_resources {
	u64 dma_mask;
	const struct freq_tbl *freq_tbl;
	unsigned int freq_tbl_size;
	const struct bw_tbl *bw_tbl_enc;
	unsigned int bw_tbl_enc_size;
	const struct bw_tbl *bw_tbl_dec;
	unsigned int bw_tbl_dec_size;
	const struct reg_val *reg_tbl;
	unsigned int reg_tbl_size;
	const char * const clks[VIDC_CLKS_NUM_MAX];
@@ -115,6 +127,8 @@ struct venus_core {
	struct clk *core1_clk;
	struct clk *core0_bus_clk;
	struct clk *core1_bus_clk;
	struct icc_path *video_path;
	struct icc_path *cpucfg_path;
	struct video_device *vdev_dec;
	struct video_device *vdev_enc;
	struct v4l2_device v4l2_dev;
+66 −1
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
 */
#include <linux/clk.h>
#include <linux/iopoll.h>
#include <linux/interconnect.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/pm_runtime.h>
@@ -388,6 +389,65 @@ static u32 load_per_type(struct venus_core *core, u32 session_type)
	return mbs_per_sec;
}

static void mbs_to_bw(struct venus_inst *inst, u32 mbs, u32 *avg, u32 *peak)
{
	const struct venus_resources *res = inst->core->res;
	const struct bw_tbl *bw_tbl;
	unsigned int num_rows, i;

	*avg = 0;
	*peak = 0;

	if (mbs == 0)
		return;

	if (inst->session_type == VIDC_SESSION_TYPE_ENC) {
		num_rows = res->bw_tbl_enc_size;
		bw_tbl = res->bw_tbl_enc;
	} else if (inst->session_type == VIDC_SESSION_TYPE_DEC) {
		num_rows = res->bw_tbl_dec_size;
		bw_tbl = res->bw_tbl_dec;
	} else {
		return;
	}

	if (!bw_tbl || num_rows == 0)
		return;

	for (i = 0; i < num_rows; i++) {
		if (mbs > bw_tbl[i].mbs_per_sec)
			break;

		if (inst->dpb_fmt & HFI_COLOR_FORMAT_10_BIT_BASE) {
			*avg = bw_tbl[i].avg_10bit;
			*peak = bw_tbl[i].peak_10bit;
		} else {
			*avg = bw_tbl[i].avg;
			*peak = bw_tbl[i].peak;
		}
	}
}

static int load_scale_bw(struct venus_core *core)
{
	struct venus_inst *inst = NULL;
	u32 mbs_per_sec, avg, peak, total_avg = 0, total_peak = 0;

	mutex_lock(&core->lock);
	list_for_each_entry(inst, &core->instances, list) {
		mbs_per_sec = load_per_instance(inst);
		mbs_to_bw(inst, mbs_per_sec, &avg, &peak);
		total_avg += avg;
		total_peak += peak;
	}
	mutex_unlock(&core->lock);

	dev_dbg(core->dev, "total: avg_bw: %u, peak_bw: %u\n",
		total_avg, total_peak);

	return icc_set_bw(core->video_path, total_avg, total_peak);
}

int venus_helper_load_scale_clocks(struct venus_core *core)
{
	const struct freq_tbl *table = core->res->freq_tbl;
@@ -431,10 +491,15 @@ int venus_helper_load_scale_clocks(struct venus_core *core)
	if (ret)
		goto err;

	ret = load_scale_bw(core);
	if (ret)
		goto err;

	return 0;

err:
	dev_err(dev, "failed to set clock rate %lu (%d)\n", freq, ret);
	dev_err(dev, "failed to set clock rate %lu or bandwidth (%d)\n",
		freq, ret);
	return ret;
}
EXPORT_SYMBOL_GPL(venus_helper_load_scale_clocks);