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

Commit df0c439a authored by Arun Menon's avatar Arun Menon
Browse files

msm: vidc: Add a new governor for vmem



The present vmem governor does not scale the vmem clock
correctly in accordance with the video core clock. Typically,
the vmem clock should always be scaled at one level below the
video core clock frequency. The vmem_plus governor achieves
this scaling for vmem clock.

Change-Id: I7e150631abfbbd2846237c4b197ccca37d09b0f4
Signed-off-by: default avatarArun Menon <avmenon@codeaurora.org>
parent d96b4bb7
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -48,6 +48,9 @@ Optional properties:
    supports hevc decoder = 0x0c000000
    supports hevc_hybrid encoder = 0x10000000
    supports hevc_hybrid decoder = 0x30000000
- qcom,imem-ab-tbl : video core frequency in Hz and corresponding imem ab value
  in kbps. The imem ab value corresponds to the clock frequency at which imem
  should operate for a particular video core frequency.
- qcom,reg-presets : list of offset-value pairs for registers to be written.
  The offsets are from the base offset specified in 'reg'. This is mainly
  used for QoS, VBIF, etc. presets for video.
@@ -153,6 +156,13 @@ Example:
			<72000 133330000 0x0c000000>, /* HEVC decoder VGA 60fps   */
			<36000 133330000 0x0c000000>, /* HEVC VGA 30 fps  */
			<36000 133330000 0x01000414>; /* Legacy encoder VGA 30 fps   */

		qcom,imem-ab-tbl =
			<75000000  1500000>, /* imem clk @ 75 Mhz  */
			<150000000 1500000>, /* imem clk @ 75 Mhz  */
			<355333333 2500000>, /* imem clk @ 170 Mhz */
			<533000000 6000000>; /* imem clk @ 320 Mhz */

		qcom,imem-size = <4096>;
		qcom,firmware-name = "venus";
		qcom,hfi-version = "3xx";
+73 −3
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ module_param(debug, bool, 0644);
enum governor_mode {
	GOVERNOR_DDR,
	GOVERNOR_VMEM,
	GOVERNOR_VMEM_PLUS,
};

struct governor {
@@ -274,6 +275,36 @@ static int __bpp(enum hal_uncompressed_format f)
	}
}

static unsigned long __calculate_vmem_plus_ab(struct vidc_bus_vote_data *d)
{
	unsigned long i = 0, vmem_plus = 0;

	if (!d->imem_ab_tbl || !d->imem_ab_tbl_size) {
		vmem_plus = 1; /* Vote for the min ab value */
		goto exit;
	}

	/* Pick up vmem frequency based on venus core frequency */
	for (i = 0; i < d->imem_ab_tbl_size; i++) {
		if (d->imem_ab_tbl[i].core_freq == d->core_freq) {
			vmem_plus = d->imem_ab_tbl[i].imem_ab;
			break;
		}
	}

	/* Incase we get an unsupported freq throw a warning
	 * and set ab to the minimum value. */
	if (!vmem_plus) {
		vmem_plus = 1;
		dprintk(VIDC_WARN,
			"could not calculate vmem ab value due to core freq mismatch\n");
		WARN_ON(1);
	}

exit:
	return vmem_plus;
}

static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d,
		enum governor_mode gm) {
	/*
@@ -308,6 +339,8 @@ static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d,
			total;
	} ddr, vmem;

	unsigned long ret = 0;

	/* Decoder parameters setup */
	scenario = SCENARIO_WORST;

@@ -573,7 +606,21 @@ static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d,
		__dump(dump, ARRAY_SIZE(dump));
	}

	return kbps(fp_round((gm == GOVERNOR_DDR ? &ddr : &vmem)->total));
	switch (gm) {
	case GOVERNOR_DDR:
		ret = kbps(fp_round(ddr.total));
		break;
	case GOVERNOR_VMEM:
		ret = kbps(fp_round(vmem.total));
		break;
	case GOVERNOR_VMEM_PLUS:
		ret = __calculate_vmem_plus_ab(d);
		break;
	default:
		dprintk(VIDC_ERR, "%s - Unknown governor\n", __func__);
	}

	return ret;
}

static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d,
@@ -620,6 +667,8 @@ static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d,
			original_write, dpb_read, dpb_write, total;
	} ddr, vmem;

	unsigned long ret = 0;

	/* Encoder Parameters setup */
	scenario = SCENARIO_WORST;

@@ -961,7 +1010,21 @@ static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d,
		__dump(dump, ARRAY_SIZE(dump));
	}

	return kbps(fp_round((gm == GOVERNOR_DDR ? &ddr : &vmem)->total));
	switch (gm) {
	case GOVERNOR_DDR:
		ret = kbps(fp_round(ddr.total));
		break;
	case GOVERNOR_VMEM:
		ret = kbps(fp_round(vmem.total));
		break;
	case GOVERNOR_VMEM_PLUS:
		ret = __calculate_vmem_plus_ab(d);
		break;
	default:
		dprintk(VIDC_ERR, "%s - Unknown governor\n", __func__);
	}

	return ret;
}

static unsigned long __calculate(struct vidc_bus_vote_data *d,
@@ -1046,7 +1109,14 @@ static struct governor governors[] = {
			.event_handler = __event_handler,
		},
	},

	{
		.mode = GOVERNOR_VMEM_PLUS,
		.devfreq_gov = {
			.name = "msm-vidc-vmem+",
			.get_target_freq = __get_target_freq,
			.event_handler = __event_handler,
		},
	},
};

static int __init msm_vidc_bw_gov_init(void)
+11 −1
Original line number Diff line number Diff line
@@ -297,6 +297,7 @@ static int msm_comm_vote_bus(struct msm_vidc_core *core)
	struct hfi_device *hdev;
	struct msm_vidc_inst *inst = NULL;
	struct vidc_bus_vote_data *vote_data = NULL;
	unsigned long core_freq = 0;

	if (!core) {
		dprintk(VIDC_ERR, "%s Invalid args: %p\n", __func__, core);
@@ -322,6 +323,9 @@ static int msm_comm_vote_bus(struct msm_vidc_core *core)
		goto fail_alloc;
	}

	core_freq = call_hfi_op(hdev, get_core_clock_rate,
			hdev->hfi_device_data, 0);

	list_for_each_entry(inst, &core->instances, list) {
		int codec = 0, yuv = 0;

@@ -344,6 +348,12 @@ static int msm_comm_vote_bus(struct msm_vidc_core *core)
			vote_data[i].power_mode = VIDC_POWER_LOW;
		else
			vote_data[i].power_mode = VIDC_POWER_NORMAL;
		if (i == 0) {
			vote_data[i].imem_ab_tbl = core->resources.imem_ab_tbl;
			vote_data[i].imem_ab_tbl_size =
				core->resources.imem_ab_tbl_size;
			vote_data[i].core_freq = core_freq;
		}

		/*
		 * TODO: support for OBP-DBP split mode hasn't been yet
@@ -1984,7 +1994,7 @@ static unsigned long msm_comm_get_clock_rate(struct msm_vidc_core *core)
	}
	hdev = core->device;

	freq = call_hfi_op(hdev, get_core_clock_rate, hdev->hfi_device_data);
	freq = call_hfi_op(hdev, get_core_clock_rate, hdev->hfi_device_data, 1);
	dprintk(VIDC_DBG, "clock freq %ld\n", freq);

	return freq;
+48 −0
Original line number Diff line number Diff line
@@ -69,6 +69,12 @@ static inline void msm_vidc_free_freq_table(
	res->load_freq_tbl = NULL;
}

static inline void msm_vidc_free_imem_ab_table(
		struct msm_vidc_platform_resources *res)
{
	res->imem_ab_tbl = NULL;
}

static inline void msm_vidc_free_reg_table(
			struct msm_vidc_platform_resources *res)
{
@@ -227,6 +233,44 @@ err_qdss_addr_tbl:
	return rc;
}

static int msm_vidc_load_imem_ab_table(struct msm_vidc_platform_resources *res)
{
	int num_elements = 0;
	struct platform_device *pdev = res->pdev;

	if (!of_find_property(pdev->dev.of_node, "qcom,imem-ab-tbl", NULL)) {
		/* optional property */
		dprintk(VIDC_DBG, "qcom,imem-freq-tbl not found\n");
		return 0;
	}

	num_elements = get_u32_array_num_elements(pdev, "qcom,imem-ab-tbl");
	num_elements /= (sizeof(*res->imem_ab_tbl) / sizeof(u32));
	if (!num_elements) {
		dprintk(VIDC_ERR, "no elements in imem ab table\n");
		return -EINVAL;
	}

	res->imem_ab_tbl = devm_kzalloc(&pdev->dev, num_elements *
			sizeof(*res->imem_ab_tbl), GFP_KERNEL);
	if (!res->imem_ab_tbl) {
		dprintk(VIDC_ERR, "Failed to alloc imem_ab_tbl\n");
		return -ENOMEM;
	}

	if (of_property_read_u32_array(pdev->dev.of_node,
		"qcom,imem-ab-tbl", (u32 *)res->imem_ab_tbl,
		num_elements * sizeof(*res->imem_ab_tbl) / sizeof(u32))) {
		dprintk(VIDC_ERR, "Failed to read imem_ab_tbl\n");
		msm_vidc_free_imem_ab_table(res);
		return -EINVAL;
	}

	res->imem_ab_tbl_size = num_elements;

	return 0;
}

static int msm_vidc_load_freq_table(struct msm_vidc_platform_resources *res)
{
	int rc = 0;
@@ -630,6 +674,10 @@ int read_platform_resources_from_dt(
		goto err_load_freq_table;
	}

	rc = msm_vidc_load_imem_ab_table(res);
	if (rc)
		dprintk(VIDC_WARN, "Failed to load freq table: %d\n", rc);

	rc = msm_vidc_load_qdss_table(res);
	if (rc)
		dprintk(VIDC_WARN, "Failed to load qdss reg table: %d\n", rc);
+7 −0
Original line number Diff line number Diff line
@@ -26,6 +26,11 @@ struct load_freq_table {
	u32 supported_codecs;
};

struct imem_ab_table {
	u32 core_freq;
	u32 imem_ab;
};

struct reg_value_pair {
	u32 reg;
	u32 value;
@@ -121,6 +126,8 @@ struct msm_vidc_platform_resources {
	uint32_t irq;
	struct load_freq_table *load_freq_tbl;
	uint32_t load_freq_tbl_size;
	struct imem_ab_table *imem_ab_tbl;
	u32 imem_ab_tbl_size;
	struct reg_set reg_set;
	struct addr_set qdss_addr_set;
	struct buffer_usage_set buffer_usage_set;
Loading