Ver código fonte

video-driver: Abstract platform resources

Move clocks, gdsc, bandwidth resources out of venus_hfi and
use the ops in variant and venus_hfi code.

Change-Id: I1be77c9d384f4eef2cb8085b75c39dc3fd3eeb86
Signed-off-by: Stanimir Varbanov <[email protected]>
Stanimir Varbanov 3 anos atrás
pai
commit
8b003fb153

+ 1 - 0
Kbuild

@@ -67,6 +67,7 @@ msm_video-objs += driver/vidc/src/msm_vidc_v4l2.o \
                   driver/vidc/src/msm_vidc_power.o \
                   driver/vidc/src/msm_vidc_probe.o \
                   driver/vidc/src/msm_vidc_dt.o \
+                  driver/vidc/src/resources.o \
                   driver/vidc/src/msm_vidc_debug.o \
                   driver/vidc/src/msm_vidc_memory.o \
                   driver/vidc/src/msm_vidc_fence.o \

+ 38 - 219
driver/variant/iris2/src/msm_vidc_iris2.c

@@ -170,202 +170,6 @@
 #define VCODEC_NOC_ERL_MAIN_ERRLOG3_LOW			0x00011238
 #define VCODEC_NOC_ERL_MAIN_ERRLOG3_HIGH		0x0001123C
 
-
-static int __disable_unprepare_clock_iris2(struct msm_vidc_core *core,
-		const char *clk_name)
-{
-	int rc = 0;
-	struct clock_info *cl;
-	bool found;
-
-	if (!core || !clk_name) {
-		d_vpr_e("%s: invalid params\n", __func__);
-		return -EINVAL;
-	}
-
-	found = false;
-	venus_hfi_for_each_clock(core, cl) {
-		if (!cl->clk) {
-			d_vpr_e("%s: invalid clock %s\n", __func__, cl->name);
-			return -EINVAL;
-		}
-		if (strcmp(cl->name, clk_name))
-			continue;
-		found = true;
-		clk_disable_unprepare(cl->clk);
-		if (cl->has_scaling)
-			__set_clk_rate(core, cl, 0);
-		cl->prev = 0;
-		d_vpr_h("%s: clock %s disable unprepared\n", __func__, cl->name);
-		break;
-	}
-	if (!found) {
-		d_vpr_e("%s: clock %s not found\n", __func__, clk_name);
-		return -EINVAL;
-	}
-
-	return rc;
-}
-
-static int __prepare_enable_clock_iris2(struct msm_vidc_core *core,
-		const char *clk_name)
-{
-	int rc = 0;
-	struct clock_info *cl;
-	bool found;
-	u64 rate = 0;
-
-	if (!core || !clk_name) {
-		d_vpr_e("%s: invalid params\n", __func__);
-		return -EINVAL;
-	}
-
-	found = false;
-	venus_hfi_for_each_clock(core, cl) {
-		if (!cl->clk) {
-			d_vpr_e("%s: invalid clock\n", __func__);
-			return -EINVAL;
-		}
-		if (strcmp(cl->name, clk_name))
-			continue;
-		found = true;
-		/*
-		 * For the clocks we control, set the rate prior to preparing
-		 * them.  Since we don't really have a load at this point, scale
-		 * it to the lowest frequency possible
-		 */
-		if (cl->has_scaling) {
-			rate = clk_round_rate(cl->clk, 0);
-			/**
-			 * source clock is already multipled with scaling ratio and __set_clk_rate
-			 * attempts to multiply again. So divide scaling ratio before calling
-			 * __set_clk_rate.
-			 */
-			rate = rate / MSM_VIDC_CLOCK_SOURCE_SCALING_RATIO;
-			__set_clk_rate(core, cl, rate);
-		}
-
-		rc = clk_prepare_enable(cl->clk);
-		if (rc) {
-			d_vpr_e("%s: failed to enable clock %s\n",
-				__func__, cl->name);
-			return rc;
-		}
-		if (!__clk_is_enabled(cl->clk)) {
-			d_vpr_e("%s: clock %s not enabled\n",
-				__func__, cl->name);
-			clk_disable_unprepare(cl->clk);
-			if (cl->has_scaling)
-				__set_clk_rate(core, cl, 0);
-			return -EINVAL;
-		}
-		d_vpr_h("%s: clock %s prepare enabled\n", __func__, cl->name);
-		break;
-	}
-	if (!found) {
-		d_vpr_e("%s: clock %s not found\n", __func__, clk_name);
-		return -EINVAL;
-	}
-
-	return rc;
-}
-
-static int __disable_regulator_iris2(struct msm_vidc_core *core,
-		const char *reg_name)
-{
-	int rc = 0;
-	struct regulator_info *rinfo;
-	bool found;
-
-	if (!core || !reg_name) {
-		d_vpr_e("%s: invalid params\n", __func__);
-		return -EINVAL;
-	}
-
-	found = false;
-	venus_hfi_for_each_regulator(core, rinfo) {
-		if (!rinfo->regulator) {
-			d_vpr_e("%s: invalid regulator %s\n",
-				__func__, rinfo->name);
-			return -EINVAL;
-		}
-		if (strcmp(rinfo->name, reg_name))
-			continue;
-		found = true;
-
-		rc = __acquire_regulator(core, rinfo);
-		if (rc) {
-			d_vpr_e("%s: failed to acquire %s, rc = %d\n",
-				__func__, rinfo->name, rc);
-			/* Bring attention to this issue */
-			WARN_ON(true);
-			return rc;
-		}
-		core->handoff_done = false;
-
-		rc = regulator_disable(rinfo->regulator);
-		if (rc) {
-			d_vpr_e("%s: failed to disable %s, rc = %d\n",
-				__func__, rinfo->name, rc);
-			return rc;
-		}
-		d_vpr_h("%s: disabled regulator %s\n", __func__, rinfo->name);
-		break;
-	}
-	if (!found) {
-		d_vpr_e("%s: regulator %s not found\n", __func__, reg_name);
-		return -EINVAL;
-	}
-
-	return rc;
-}
-
-static int __enable_regulator_iris2(struct msm_vidc_core *core,
-		const char *reg_name)
-{
-	int rc = 0;
-	struct regulator_info *rinfo;
-	bool found;
-
-	if (!core || !reg_name) {
-		d_vpr_e("%s: invalid params\n", __func__);
-		return -EINVAL;
-	}
-
-	found = false;
-	venus_hfi_for_each_regulator(core, rinfo) {
-		if (!rinfo->regulator) {
-			d_vpr_e("%s: invalid regulator %s\n",
-				__func__, rinfo->name);
-			return -EINVAL;
-		}
-		if (strcmp(rinfo->name, reg_name))
-			continue;
-		found = true;
-
-		rc = regulator_enable(rinfo->regulator);
-		if (rc) {
-			d_vpr_e("%s: failed to enable %s, rc = %d\n",
-				__func__, rinfo->name, rc);
-			return rc;
-		}
-		if (!regulator_is_enabled(rinfo->regulator)) {
-			d_vpr_e("%s: regulator %s not enabled\n",
-				__func__, rinfo->name);
-			regulator_disable(rinfo->regulator);
-			return -EINVAL;
-		}
-		d_vpr_h("%s: enabled regulator %s\n", __func__, rinfo->name);
-		break;
-	}
-	if (!found) {
-		d_vpr_e("%s: regulator %s not found\n", __func__, reg_name);
-		return -EINVAL;
-	}
-
-	return rc;
-}
-
 static int __interrupt_init_iris2(struct msm_vidc_core *vidc_core)
 {
 	struct msm_vidc_core *core = vidc_core;
@@ -445,6 +249,7 @@ static int __setup_ucregion_memory_map_iris2(struct msm_vidc_core *vidc_core)
 
 static int __power_off_iris2_hardware(struct msm_vidc_core *core)
 {
+	const struct msm_vidc_resources_ops *res_ops = core->res_ops;
 	int rc = 0, i;
 	u32 value = 0;
 
@@ -517,12 +322,12 @@ static int __power_off_iris2_hardware(struct msm_vidc_core *core)
 
 disable_power:
 	/* power down process */
-	rc = __disable_regulator_iris2(core, "vcodec");
+	rc = res_ops->gdsc_off(core, "vcodec");
 	if (rc) {
 		d_vpr_e("%s: disable regulator vcodec failed\n", __func__);
 		rc = 0;
 	}
-	rc = __disable_unprepare_clock_iris2(core, "vcodec_clk");
+	rc = res_ops->clk_disable(core, "vcodec_clk");
 	if (rc) {
 		d_vpr_e("%s: disable unprepare vcodec_clk failed\n", __func__);
 		rc = 0;
@@ -533,6 +338,7 @@ disable_power:
 
 static int __power_off_iris2_controller(struct msm_vidc_core *core)
 {
+	const struct msm_vidc_resources_ops *res_ops = core->res_ops;
 	int rc = 0;
 
 	/*
@@ -575,27 +381,27 @@ static int __power_off_iris2_controller(struct msm_vidc_core *core)
 		d_vpr_h("%s: debug bridge release failed\n", __func__);
 
 	/* Turn off MVP MVS0C core clock */
-	rc = __disable_unprepare_clock_iris2(core, "core_clk");
+	rc = res_ops->clk_disable(core, "core_clk");
 	if (rc) {
 		d_vpr_e("%s: disable unprepare core_clk failed\n", __func__);
 		rc = 0;
 	}
 
 	/* Disable GCC_VIDEO_AXI0_CLK clock */
-	rc = __disable_unprepare_clock_iris2(core, "gcc_video_axi0");
+	rc = res_ops->clk_disable(core, "gcc_video_axi0");
 	if (rc) {
 		d_vpr_e("%s: disable unprepare gcc_video_axi0 failed\n", __func__);
 		rc = 0;
 	}
 
-	rc = call_venus_op(core, reset_ahb2axi_bridge, core);
+	rc = res_ops->reset_bridge(core);
 	if (rc) {
-		d_vpr_e("%s: reset ahb2axi bridge failed\n", __func__);
+		d_vpr_e("%s: reset bridge failed\n", __func__);
 		rc = 0;
 	}
 
 	/* power down process */
-	rc = __disable_regulator_iris2(core, "iris-ctl");
+	rc = res_ops->gdsc_off(core, "iris-ctl");
 	if (rc) {
 		d_vpr_e("%s: disable regulator iris-ctl failed\n", __func__);
 		rc = 0;
@@ -606,6 +412,7 @@ static int __power_off_iris2_controller(struct msm_vidc_core *core)
 
 static int __power_off_iris2(struct msm_vidc_core *core)
 {
+	const struct msm_vidc_resources_ops *res_ops = core->res_ops;
 	int rc = 0;
 
 	if (!core || !core->capabilities) {
@@ -620,7 +427,7 @@ static int __power_off_iris2(struct msm_vidc_core *core)
 	 * Reset video_cc_mvs0_clk_src value to resolve MMRM high video
 	 * clock projection issue.
 	 */
-	rc = __set_clocks(core, 0);
+	rc = res_ops->set_clks(core, 0);
 	if (rc)
 		d_vpr_e("%s: resetting clocks failed\n", __func__);
 
@@ -630,7 +437,7 @@ static int __power_off_iris2(struct msm_vidc_core *core)
 	if (__power_off_iris2_controller(core))
 		d_vpr_e("%s: failed to power off controller\n", __func__);
 
-	if (__unvote_buses(core))
+	if (res_ops->set_bw(core, 0, 0))
 		d_vpr_e("%s: failed to unvote buses\n", __func__);
 
 	if (!(core->intr_status & WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS2))
@@ -644,64 +451,69 @@ static int __power_off_iris2(struct msm_vidc_core *core)
 
 static int __power_on_iris2_controller(struct msm_vidc_core *core)
 {
+	const struct msm_vidc_resources_ops *res_ops = core->res_ops;
 	int rc = 0;
 
-	rc = __enable_regulator_iris2(core, "iris-ctl");
+	rc = res_ops->gdsc_on(core, "iris-ctl");
 	if (rc)
 		goto fail_regulator;
 
-	rc = call_venus_op(core, reset_ahb2axi_bridge, core);
+	rc = res_ops->reset_bridge(core);
 	if (rc)
 		goto fail_reset_ahb2axi;
 
-	rc = __prepare_enable_clock_iris2(core, "gcc_video_axi0");
+	rc = res_ops->clk_enable(core, "gcc_video_axi0");
 	if (rc)
 		goto fail_clk_axi;
 
-	rc = __prepare_enable_clock_iris2(core, "core_clk");
+	rc = res_ops->clk_enable(core, "core_clk");
 	if (rc)
 		goto fail_clk_controller;
 
 	return 0;
 
 fail_clk_controller:
-	__disable_unprepare_clock_iris2(core, "gcc_video_axi0");
+	res_ops->clk_disable(core, "gcc_video_axi0");
 fail_clk_axi:
 fail_reset_ahb2axi:
-	__disable_regulator_iris2(core, "iris-ctl");
+	res_ops->gdsc_off(core, "iris-ctl");
 fail_regulator:
 	return rc;
 }
 
 static int __power_on_iris2_hardware(struct msm_vidc_core *core)
 {
+	const struct msm_vidc_resources_ops *res_ops = core->res_ops;
 	int rc = 0;
 
-	rc = __enable_regulator_iris2(core, "vcodec");
+	rc = res_ops->gdsc_on(core, "vcodec");
 	if (rc)
 		goto fail_regulator;
 
-	rc = __prepare_enable_clock_iris2(core, "vcodec_clk");
+	rc = res_ops->clk_enable(core, "vcodec_clk");
 	if (rc)
 		goto fail_clk_controller;
 
 	return 0;
 
 fail_clk_controller:
-	__disable_regulator_iris2(core, "vcodec");
+	res_ops->gdsc_off(core, "vcodec");
 fail_regulator:
 	return rc;
 }
 
 static int __power_on_iris2(struct msm_vidc_core *core)
 {
+	const struct msm_vidc_resources_ops *res_ops = core->res_ops;
+	struct allowed_clock_rates_table *clk_tbl;
+	u32 freq = 0;
 	int rc = 0;
 
 	if (core->power_enabled)
 		return 0;
 
 	/* Vote for all hardware resources */
-	rc = __vote_buses(core, INT_MAX, INT_MAX);
+	rc = res_ops->set_bw(core, INT_MAX, INT_MAX);
 	if (rc) {
 		d_vpr_e("%s: failed to vote buses, rc %d\n", __func__, rc);
 		goto fail_vote_buses;
@@ -721,16 +533,23 @@ static int __power_on_iris2(struct msm_vidc_core *core)
 	/* video controller and hardware powered on successfully */
 	core->power_enabled = true;
 
-	rc = __scale_clocks(core);
+	clk_tbl = core->dt->allowed_clks_tbl;
+	freq = core->power.clk_freq ? core->power.clk_freq :
+				      clk_tbl[0].clock_rate;
+
+	rc = res_ops->set_clks(core, freq);
 	if (rc) {
 		d_vpr_e("%s: failed to scale clocks\n", __func__);
 		rc = 0;
 	}
+
+	core->power.clk_freq = freq;
+
 	/*
 	 * Re-program all of the registers that get reset as a result of
 	 * regulator_disable() and _enable()
 	 */
-	__set_registers(core);
+	res_ops->set_regs(core);
 
 	__interrupt_init_iris2(core);
 	core->intr_status = 0;
@@ -741,7 +560,7 @@ static int __power_on_iris2(struct msm_vidc_core *core)
 fail_power_on_hardware:
 	__power_off_iris2_controller(core);
 fail_power_on_controller:
-	__unvote_buses(core);
+	res_ops->set_bw(core, 0, 0);
 fail_vote_buses:
 	core->power_enabled = false;
 	return rc;
@@ -1185,7 +1004,6 @@ static struct msm_vidc_venus_ops iris2_ops = {
 	.boot_firmware = __boot_firmware_iris2,
 	.raise_interrupt = __raise_interrupt_iris2,
 	.clear_interrupt = __clear_interrupt_iris2,
-	.reset_ahb2axi_bridge = __reset_ahb2axi_bridge,
 	.power_on = __power_on_iris2,
 	.power_off = __power_off_iris2,
 	.prepare_pc = __prepare_pc_iris2,
@@ -1214,6 +1032,7 @@ int msm_vidc_init_iris2(struct msm_vidc_core *core)
 	d_vpr_h("%s()\n", __func__);
 	core->venus_ops = &iris2_ops;
 	core->session_ops = &msm_session_ops;
+	core->res_ops = get_resources_ops();
 
 	return 0;
 }

+ 33 - 216
driver/variant/iris3/src/msm_vidc_iris3.c

@@ -176,202 +176,6 @@
 #define VCODEC_NOC_ERL_MAIN_ERRLOG3_LOW			0x00011238
 #define VCODEC_NOC_ERL_MAIN_ERRLOG3_HIGH		0x0001123C
 
-
-static int __disable_unprepare_clock_iris3(struct msm_vidc_core *core,
-		const char *clk_name)
-{
-	int rc = 0;
-	struct clock_info *cl;
-	bool found;
-
-	if (!core || !clk_name) {
-		d_vpr_e("%s: invalid params\n", __func__);
-		return -EINVAL;
-	}
-
-	found = false;
-	venus_hfi_for_each_clock(core, cl) {
-		if (!cl->clk) {
-			d_vpr_e("%s: invalid clock %s\n", __func__, cl->name);
-			return -EINVAL;
-		}
-		if (strcmp(cl->name, clk_name))
-			continue;
-		found = true;
-		clk_disable_unprepare(cl->clk);
-		if (cl->has_scaling)
-			__set_clk_rate(core, cl, 0);
-		cl->prev = 0;
-		d_vpr_h("%s: clock %s disable unprepared\n", __func__, cl->name);
-		break;
-	}
-	if (!found) {
-		d_vpr_e("%s: clock %s not found\n", __func__, clk_name);
-		return -EINVAL;
-	}
-
-	return rc;
-}
-
-static int __prepare_enable_clock_iris3(struct msm_vidc_core *core,
-		const char *clk_name)
-{
-	int rc = 0;
-	struct clock_info *cl;
-	bool found;
-	u64 rate = 0;
-
-	if (!core || !clk_name) {
-		d_vpr_e("%s: invalid params\n", __func__);
-		return -EINVAL;
-	}
-
-	found = false;
-	venus_hfi_for_each_clock(core, cl) {
-		if (!cl->clk) {
-			d_vpr_e("%s: invalid clock\n", __func__);
-			return -EINVAL;
-		}
-		if (strcmp(cl->name, clk_name))
-			continue;
-		found = true;
-		/*
-		 * For the clocks we control, set the rate prior to preparing
-		 * them.  Since we don't really have a load at this point, scale
-		 * it to the lowest frequency possible
-		 */
-		if (cl->has_scaling) {
-			rate = clk_round_rate(cl->clk, 0);
-			/**
-			 * source clock is already multipled with scaling ratio and __set_clk_rate
-			 * attempts to multiply again. So divide scaling ratio before calling
-			 * __set_clk_rate.
-			 */
-			rate = rate / MSM_VIDC_CLOCK_SOURCE_SCALING_RATIO;
-			__set_clk_rate(core, cl, rate);
-		}
-
-		rc = clk_prepare_enable(cl->clk);
-		if (rc) {
-			d_vpr_e("%s: failed to enable clock %s\n",
-				__func__, cl->name);
-			return rc;
-		}
-		if (!__clk_is_enabled(cl->clk)) {
-			d_vpr_e("%s: clock %s not enabled\n",
-				__func__, cl->name);
-			clk_disable_unprepare(cl->clk);
-			if (cl->has_scaling)
-				__set_clk_rate(core, cl, 0);
-			return -EINVAL;
-		}
-		d_vpr_h("%s: clock %s prepare enabled\n", __func__, cl->name);
-		break;
-	}
-	if (!found) {
-		d_vpr_e("%s: clock %s not found\n", __func__, clk_name);
-		return -EINVAL;
-	}
-
-	return rc;
-}
-
-static int __disable_regulator_iris3(struct msm_vidc_core *core,
-		const char *reg_name)
-{
-	int rc = 0;
-	struct regulator_info *rinfo;
-	bool found;
-
-	if (!core || !reg_name) {
-		d_vpr_e("%s: invalid params\n", __func__);
-		return -EINVAL;
-	}
-
-	found = false;
-	venus_hfi_for_each_regulator(core, rinfo) {
-		if (!rinfo->regulator) {
-			d_vpr_e("%s: invalid regulator %s\n",
-				__func__, rinfo->name);
-			return -EINVAL;
-		}
-		if (strcmp(rinfo->name, reg_name))
-			continue;
-		found = true;
-
-		rc = __acquire_regulator(core, rinfo);
-		if (rc) {
-			d_vpr_e("%s: failed to acquire %s, rc = %d\n",
-				__func__, rinfo->name, rc);
-			/* Bring attention to this issue */
-			WARN_ON(true);
-			return rc;
-		}
-		core->handoff_done = false;
-
-		rc = regulator_disable(rinfo->regulator);
-		if (rc) {
-			d_vpr_e("%s: failed to disable %s, rc = %d\n",
-				__func__, rinfo->name, rc);
-			return rc;
-		}
-		d_vpr_h("%s: disabled regulator %s\n", __func__, rinfo->name);
-		break;
-	}
-	if (!found) {
-		d_vpr_e("%s: regulator %s not found\n", __func__, reg_name);
-		return -EINVAL;
-	}
-
-	return rc;
-}
-
-static int __enable_regulator_iris3(struct msm_vidc_core *core,
-		const char *reg_name)
-{
-	int rc = 0;
-	struct regulator_info *rinfo;
-	bool found;
-
-	if (!core || !reg_name) {
-		d_vpr_e("%s: invalid params\n", __func__);
-		return -EINVAL;
-	}
-
-	found = false;
-	venus_hfi_for_each_regulator(core, rinfo) {
-		if (!rinfo->regulator) {
-			d_vpr_e("%s: invalid regulator %s\n",
-				__func__, rinfo->name);
-			return -EINVAL;
-		}
-		if (strcmp(rinfo->name, reg_name))
-			continue;
-		found = true;
-
-		rc = regulator_enable(rinfo->regulator);
-		if (rc) {
-			d_vpr_e("%s: failed to enable %s, rc = %d\n",
-				__func__, rinfo->name, rc);
-			return rc;
-		}
-		if (!regulator_is_enabled(rinfo->regulator)) {
-			d_vpr_e("%s: regulator %s not enabled\n",
-				__func__, rinfo->name);
-			regulator_disable(rinfo->regulator);
-			return -EINVAL;
-		}
-		d_vpr_h("%s: enabled regulator %s\n", __func__, rinfo->name);
-		break;
-	}
-	if (!found) {
-		d_vpr_e("%s: regulator %s not found\n", __func__, reg_name);
-		return -EINVAL;
-	}
-
-	return rc;
-}
-
 static int __interrupt_init_iris3(struct msm_vidc_core *vidc_core)
 {
 	struct msm_vidc_core *core = vidc_core;
@@ -465,6 +269,7 @@ static bool is_iris3_hw_power_collapsed(struct msm_vidc_core *core)
 
 static int __power_off_iris3_hardware(struct msm_vidc_core *core)
 {
+	const struct msm_vidc_resources_ops *res_ops = core->res_ops;
 	int rc = 0, i;
 	u32 value = 0;
 	bool pwr_collapsed = false;
@@ -556,12 +361,13 @@ static int __power_off_iris3_hardware(struct msm_vidc_core *core)
 
 disable_power:
 	/* power down process */
-	rc = __disable_regulator_iris3(core, "vcodec");
+	rc = res_ops->gdsc_off(core, "vcodec");
 	if (rc) {
 		d_vpr_e("%s: disable regulator vcodec failed\n", __func__);
 		rc = 0;
 	}
-	rc = __disable_unprepare_clock_iris3(core, "vcodec_clk");
+
+	rc = res_ops->clk_disable(core, "vcodec_clk");
 	if (rc) {
 		d_vpr_e("%s: disable unprepare vcodec_clk failed\n", __func__);
 		rc = 0;
@@ -572,6 +378,7 @@ disable_power:
 
 static int __power_off_iris3_controller(struct msm_vidc_core *core)
 {
+	const struct msm_vidc_resources_ops *res_ops = core->res_ops;
 	int rc = 0;
 
 	/*
@@ -632,14 +439,14 @@ static int __power_off_iris3_controller(struct msm_vidc_core *core)
 		return rc;
 
 	/* Turn off MVP MVS0C core clock */
-	rc = __disable_unprepare_clock_iris3(core, "core_clk");
+	rc = res_ops->clk_disable(core, "core_clk");
 	if (rc) {
 		d_vpr_e("%s: disable unprepare core_clk failed\n", __func__);
 		rc = 0;
 	}
 
 	/* power down process */
-	rc = __disable_regulator_iris3(core, "iris-ctl");
+	rc = res_ops->gdsc_off(core, "iris-ctl");
 	if (rc) {
 		d_vpr_e("%s: disable regulator iris-ctl failed\n", __func__);
 		rc = 0;
@@ -650,6 +457,7 @@ static int __power_off_iris3_controller(struct msm_vidc_core *core)
 
 static int __power_off_iris3(struct msm_vidc_core *core)
 {
+	const struct msm_vidc_resources_ops *res_ops = core->res_ops;
 	int rc = 0;
 
 	if (!core || !core->capabilities) {
@@ -664,7 +472,7 @@ static int __power_off_iris3(struct msm_vidc_core *core)
 	 * Reset video_cc_mvs0_clk_src value to resolve MMRM high video
 	 * clock projection issue.
 	 */
-	rc = __set_clocks(core, 0);
+	rc = res_ops->set_clks(core, 0);
 	if (rc)
 		d_vpr_e("%s: resetting clocks failed\n", __func__);
 
@@ -674,7 +482,7 @@ static int __power_off_iris3(struct msm_vidc_core *core)
 	if (__power_off_iris3_controller(core))
 		d_vpr_e("%s: failed to power off controller\n", __func__);
 
-	if (__unvote_buses(core))
+	if (res_ops->set_bw(core, 0, 0))
 		d_vpr_e("%s: failed to unvote buses\n", __func__);
 
 	if (!(core->intr_status & WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS3))
@@ -688,64 +496,69 @@ static int __power_off_iris3(struct msm_vidc_core *core)
 
 static int __power_on_iris3_controller(struct msm_vidc_core *core)
 {
+	const struct msm_vidc_resources_ops *res_ops = core->res_ops;
 	int rc = 0;
 
-	rc = __enable_regulator_iris3(core, "iris-ctl");
+	rc = res_ops->gdsc_on(core, "iris-ctl");
 	if (rc)
 		goto fail_regulator;
 
-	rc = call_venus_op(core, reset_ahb2axi_bridge, core);
+	rc = res_ops->reset_bridge(core);
 	if (rc)
 		goto fail_reset_ahb2axi;
 
-	rc = __prepare_enable_clock_iris3(core, "gcc_video_axi0");
+	rc = res_ops->clk_enable(core, "gcc_video_axi0");
 	if (rc)
 		goto fail_clk_axi;
 
-	rc = __prepare_enable_clock_iris3(core, "core_clk");
+	rc = res_ops->clk_enable(core, "core_clk");
 	if (rc)
 		goto fail_clk_controller;
 
 	return 0;
 
 fail_clk_controller:
-	__disable_unprepare_clock_iris3(core, "gcc_video_axi0");
+	res_ops->clk_disable(core, "gcc_video_axi0");
 fail_clk_axi:
 fail_reset_ahb2axi:
-	__disable_regulator_iris3(core, "iris-ctl");
+	res_ops->gdsc_off(core, "iris-ctl");
 fail_regulator:
 	return rc;
 }
 
 static int __power_on_iris3_hardware(struct msm_vidc_core *core)
 {
+	const struct msm_vidc_resources_ops *res_ops = core->res_ops;
 	int rc = 0;
 
-	rc = __enable_regulator_iris3(core, "vcodec");
+	rc = res_ops->gdsc_on(core, "vcodec");
 	if (rc)
 		goto fail_regulator;
 
-	rc = __prepare_enable_clock_iris3(core, "vcodec_clk");
+	rc = res_ops->clk_enable(core, "vcodec_clk");
 	if (rc)
 		goto fail_clk_controller;
 
 	return 0;
 
 fail_clk_controller:
-	__disable_regulator_iris3(core, "vcodec");
+	res_ops->gdsc_off(core, "vcodec");
 fail_regulator:
 	return rc;
 }
 
 static int __power_on_iris3(struct msm_vidc_core *core)
 {
+	const struct msm_vidc_resources_ops *res_ops = core->res_ops;
+	struct allowed_clock_rates_table *clk_tbl;
+	u32 freq = 0;
 	int rc = 0;
 
 	if (core->power_enabled)
 		return 0;
 
 	/* Vote for all hardware resources */
-	rc = __vote_buses(core, INT_MAX, INT_MAX);
+	rc = res_ops->set_bw(core, INT_MAX, INT_MAX);
 	if (rc) {
 		d_vpr_e("%s: failed to vote buses, rc %d\n", __func__, rc);
 		goto fail_vote_buses;
@@ -765,7 +578,11 @@ static int __power_on_iris3(struct msm_vidc_core *core)
 	/* video controller and hardware powered on successfully */
 	core->power_enabled = true;
 
-	rc = __scale_clocks(core);
+	clk_tbl = core->dt->allowed_clks_tbl;
+	freq = core->power.clk_freq ? core->power.clk_freq :
+				      clk_tbl[0].clock_rate;
+
+	rc = res_ops->set_clks(core, freq);
 	if (rc) {
 		d_vpr_e("%s: failed to scale clocks\n", __func__);
 		rc = 0;
@@ -774,7 +591,7 @@ static int __power_on_iris3(struct msm_vidc_core *core)
 	 * Re-program all of the registers that get reset as a result of
 	 * regulator_disable() and _enable()
 	 */
-	__set_registers(core);
+	res_ops->set_regs(core);
 
 	__interrupt_init_iris3(core);
 	core->intr_status = 0;
@@ -785,7 +602,7 @@ static int __power_on_iris3(struct msm_vidc_core *core)
 fail_power_on_hardware:
 	__power_off_iris3_controller(core);
 fail_power_on_controller:
-	__unvote_buses(core);
+	res_ops->set_bw(core, 0, 0);
 fail_vote_buses:
 	core->power_enabled = false;
 	return rc;
@@ -1263,7 +1080,6 @@ static struct msm_vidc_venus_ops iris3_ops = {
 	.boot_firmware = __boot_firmware_iris3,
 	.raise_interrupt = __raise_interrupt_iris3,
 	.clear_interrupt = __clear_interrupt_iris3,
-	.reset_ahb2axi_bridge = __reset_ahb2axi_bridge,
 	.power_on = __power_on_iris3,
 	.power_off = __power_off_iris3,
 	.prepare_pc = __prepare_pc_iris3,
@@ -1292,6 +1108,7 @@ int msm_vidc_init_iris3(struct msm_vidc_core *core)
 	d_vpr_h("%s()\n", __func__);
 	core->venus_ops = &iris3_ops;
 	core->session_ops = &msm_session_ops;
+	core->res_ops = get_resources_ops();
 
 	return 0;
 }

+ 2 - 1
driver/vidc/inc/msm_vidc_core.h

@@ -10,6 +10,7 @@
 
 #include "msm_vidc_internal.h"
 #include "venus_hfi_queue.h"
+#include "resources.h"
 
 struct msm_vidc_core;
 
@@ -21,7 +22,6 @@ struct msm_vidc_core;
 
 struct msm_vidc_venus_ops {
 	int (*boot_firmware)(struct msm_vidc_core *core);
-	int (*reset_ahb2axi_bridge)(struct msm_vidc_core *core);
 	int (*raise_interrupt)(struct msm_vidc_core *core);
 	int (*clear_interrupt)(struct msm_vidc_core *core);
 	int (*prepare_pc)(struct msm_vidc_core *core);
@@ -108,6 +108,7 @@ struct msm_vidc_core {
 	struct vb2_mem_ops                    *vb2_mem_ops;
 	struct v4l2_m2m_ops                   *v4l2_m2m_ops;
 	struct msm_vidc_venus_ops             *venus_ops;
+	const struct msm_vidc_resources_ops   *res_ops;
 	struct msm_vidc_session_ops           *session_ops;
 	struct msm_vidc_memory_ops            *mem_ops;
 	struct media_device_ops               *media_device_ops;

+ 2 - 0
driver/vidc/inc/msm_vidc_dt.h

@@ -135,7 +135,9 @@ struct clock_info {
 	bool has_scaling;
 	bool has_mem_retention;
 	u64 prev;
+#ifdef CONFIG_MSM_MMRM
 	struct mmrm_client *mmrm_client;
+#endif
 };
 
 struct clock_set {

+ 35 - 0
driver/vidc/inc/resources.h

@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _MSM_VIDC_RESOURCES_H_
+#define _MSM_VIDC_RESOURCES_H_
+
+struct msm_vidc_core;
+
+struct msm_vidc_resources_ops {
+	int (*get)(struct msm_vidc_core *core);
+	void (*put)(struct msm_vidc_core *core);
+
+	int (*reset_bridge)(struct msm_vidc_core *core);
+
+	int (*gdsc_on)(struct msm_vidc_core *core, const char *name);
+	int (*gdsc_off)(struct msm_vidc_core *core, const char *name);
+	int (*gdsc_hw_ctrl)(struct msm_vidc_core *core);
+	int (*gdsc_sw_ctrl)(struct msm_vidc_core *core);
+
+	int (*llcc)(struct msm_vidc_core *core, bool enable);
+	int (*set_bw)(struct msm_vidc_core *core, unsigned long bw_ddr,
+		      unsigned long bw_llcc);
+	int (*set_clks)(struct msm_vidc_core *core, u64 rate);
+
+	int (*clk_disable)(struct msm_vidc_core *core, const char *name);
+	int (*clk_enable)(struct msm_vidc_core *core, const char *name);
+
+	int (*set_regs)(struct msm_vidc_core *core);
+};
+
+const struct msm_vidc_resources_ops *get_resources_ops(void);
+
+#endif

+ 0 - 20
driver/vidc/inc/venus_hfi.h

@@ -80,27 +80,7 @@ int __write_register(struct msm_vidc_core *core,
 int __read_register(struct msm_vidc_core *core, u32 reg, u32 *value);
 int __read_register_with_poll_timeout(struct msm_vidc_core *core,
 	u32 reg, u32 mask, u32 exp_val, u32 sleep_us, u32 timeout_us);
-int __set_clocks(struct msm_vidc_core *core, u32 freq);
-int __scale_clocks(struct msm_vidc_core *core);
-int __set_clk_rate(struct msm_vidc_core *core,
-	struct clock_info *cl, u64 rate);
-int __acquire_regulator(struct msm_vidc_core *core,
-	struct regulator_info *rinfo);
-int __unvote_buses(struct msm_vidc_core *core);
-int __vote_buses(struct msm_vidc_core *core, unsigned long bw_ddr,
-	unsigned long bw_llcc);
 int __prepare_pc(struct msm_vidc_core *core);
-int __set_registers(struct msm_vidc_core *core);
-
-int __reset_ahb2axi_bridge(struct msm_vidc_core *core);
-int __clock_config_on_enable(struct msm_vidc_core *core);
-int __interrupt_init(struct msm_vidc_core *core);
-int __setup_ucregion_memmap(struct msm_vidc_core *core);
-int __raise_interrupt(struct msm_vidc_core *core);
-int __power_on(struct msm_vidc_core *core);
-int __power_off(struct msm_vidc_core *core);
 bool __core_in_valid_state(struct msm_vidc_core *core);
-int __load_fw(struct msm_vidc_core *core);
-void __unload_fw(struct msm_vidc_core *core);
 
 #endif // _VENUS_HFI_H_

+ 14 - 0
driver/vidc/src/msm_vidc_probe.c

@@ -229,6 +229,7 @@ video_reg_failed:
 	return rc;
 }
 
+#ifdef CONFIG_MSM_MMRM
 static int msm_vidc_check_mmrm_support(struct msm_vidc_core *core)
 {
 	int rc = 0;
@@ -250,6 +251,19 @@ exit:
 	d_vpr_h("%s: %d\n", __func__, core->capabilities[MMRM].value);
 	return rc;
 }
+#else
+static int msm_vidc_check_mmrm_support(struct msm_vidc_core *core)
+{
+	if (!core || !core->capabilities) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	core->capabilities[MMRM].value = 0;
+
+	return 0;
+}
+#endif
 
 static int msm_vidc_deinitialize_core(struct msm_vidc_core *core)
 {

+ 1148 - 0
driver/vidc/src/resources.c

@@ -0,0 +1,1148 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ */
+/* Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved. */
+
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <linux/interconnect.h>
+
+#include "msm_vidc_core.h"
+#include "msm_vidc_debug.h"
+#include "msm_vidc_dt.h"
+#include "msm_vidc_power.h"
+#include "venus_hfi.h"
+
+/* Less than 50MBps is treated as trivial BW change */
+#define TRIVIAL_BW_THRESHOLD 50000
+#define TRIVIAL_BW_CHANGE(a, b) \
+	((a) > (b) ? (a) - (b) < TRIVIAL_BW_THRESHOLD : \
+		(b) - (a) < TRIVIAL_BW_THRESHOLD)
+
+enum reset_state {
+	INIT = 1,
+	ASSERT,
+	DEASSERT,
+};
+
+static void __fatal_error(bool fatal)
+{
+	WARN_ON(fatal);
+}
+
+static bool is_sys_cache_present(struct msm_vidc_core *core)
+{
+	return core->dt->sys_cache_present;
+}
+
+static void __deinit_clocks(struct msm_vidc_core *core)
+{
+	struct clock_info *cl;
+
+	core->power.clk_freq = 0;
+	venus_hfi_for_each_clock_reverse(core, cl) {
+		if (cl->clk) {
+			clk_put(cl->clk);
+			cl->clk = NULL;
+		}
+	}
+}
+
+static int __init_clocks(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	struct clock_info *cl = NULL;
+
+	if (!core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	venus_hfi_for_each_clock(core, cl) {
+		d_vpr_h("%s: scalable? %d, count %d\n",
+				cl->name, cl->has_scaling, cl->count);
+	}
+
+	venus_hfi_for_each_clock(core, cl) {
+		if (!cl->clk) {
+			cl->clk = clk_get(&core->pdev->dev, cl->name);
+			if (IS_ERR_OR_NULL(cl->clk)) {
+				d_vpr_e("Failed to get clock: %s\n", cl->name);
+				rc = PTR_ERR(cl->clk) ?
+					PTR_ERR(cl->clk) : -EINVAL;
+				cl->clk = NULL;
+				goto err_clk_get;
+			}
+		}
+	}
+	core->power.clk_freq = 0;
+	return 0;
+
+err_clk_get:
+	__deinit_clocks(core);
+	return rc;
+}
+
+static int __handle_reset_clk(struct msm_vidc_core *core,
+			int reset_index, enum reset_state state)
+{
+	int rc = 0;
+	struct msm_vidc_dt *dt = core->dt;
+	struct reset_control *rst;
+	struct reset_set *rst_set = &dt->reset_set;
+
+	if (!rst_set->reset_tbl)
+		return 0;
+
+	rst = rst_set->reset_tbl[reset_index].rst;
+	d_vpr_h("reset_clk: name %s reset_state %d rst %pK\n",
+		rst_set->reset_tbl[reset_index].name, state, rst);
+
+	switch (state) {
+	case INIT:
+		if (rst)
+			goto skip_reset_init;
+
+		rst = devm_reset_control_get(&core->pdev->dev,
+				rst_set->reset_tbl[reset_index].name);
+		if (IS_ERR(rst))
+			rc = PTR_ERR(rst);
+
+		rst_set->reset_tbl[reset_index].rst = rst;
+		break;
+	case ASSERT:
+		if (!rst) {
+			rc = PTR_ERR(rst);
+			goto failed_to_reset;
+		}
+
+		rc = reset_control_assert(rst);
+		break;
+	case DEASSERT:
+		if (!rst) {
+			rc = PTR_ERR(rst);
+			goto failed_to_reset;
+		}
+		rc = reset_control_deassert(rst);
+		break;
+	default:
+		d_vpr_e("%s: invalid reset request\n", __func__);
+		if (rc)
+			goto failed_to_reset;
+	}
+
+	return 0;
+
+skip_reset_init:
+failed_to_reset:
+	return rc;
+}
+
+static int __reset_ahb2axi_bridge(struct msm_vidc_core *core)
+{
+	int rc, i;
+
+	if (!core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < core->dt->reset_set.count; i++) {
+		rc = __handle_reset_clk(core, i, ASSERT);
+		if (rc) {
+			d_vpr_e("failed to assert reset clocks\n");
+			goto failed_to_reset;
+		}
+
+		/* wait for deassert */
+		usleep_range(1000, 1100);
+	}
+
+	for (i = 0; i < core->dt->reset_set.count; i++) {
+		rc = __handle_reset_clk(core, i, DEASSERT);
+		if (rc) {
+			d_vpr_e("failed to deassert reset clocks\n");
+			goto failed_to_reset;
+		}
+	}
+
+	return 0;
+
+failed_to_reset:
+	return rc;
+}
+
+static void __deinit_bus(struct msm_vidc_core *core)
+{
+	struct bus_info *bus = NULL;
+
+	if (!core)
+		return;
+
+	core->power.bw_ddr = 0;
+	core->power.bw_llcc = 0;
+
+	venus_hfi_for_each_bus_reverse(core, bus) {
+		if (!bus->path)
+			continue;
+		icc_put(bus->path);
+		bus->path = NULL;
+	}
+}
+
+static int __init_bus(struct msm_vidc_core *core)
+{
+	struct bus_info *bus = NULL;
+	int rc = 0;
+
+	if (!core) {
+		d_vpr_e("%s: invalid param\n", __func__);
+		return -EINVAL;
+	}
+
+	venus_hfi_for_each_bus(core, bus) {
+		if (!strcmp(bus->name, "venus-llcc")) {
+			if (msm_vidc_syscache_disable) {
+				d_vpr_h("Skipping LLC bus init: %s\n",
+					bus->name);
+				continue;
+			}
+		}
+		bus->path = of_icc_get(bus->dev, bus->name);
+		if (IS_ERR_OR_NULL(bus->path)) {
+			rc = PTR_ERR(bus->path) ?
+				PTR_ERR(bus->path) : -EBADHANDLE;
+
+			d_vpr_e("Failed to register bus %s: %d\n",
+					bus->name, rc);
+			bus->path = NULL;
+			goto err_add_dev;
+		}
+	}
+
+	return 0;
+
+err_add_dev:
+	__deinit_bus(core);
+	return rc;
+}
+
+static int __acquire_regulator(struct msm_vidc_core *core,
+			       struct regulator_info *rinfo)
+{
+	int rc = 0;
+
+	if (!core || !rinfo) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (rinfo->has_hw_power_collapse) {
+		if (!rinfo->regulator) {
+			d_vpr_e("%s: invalid regulator\n", __func__);
+			rc = -EINVAL;
+			goto exit;
+		}
+
+		if (regulator_get_mode(rinfo->regulator) ==
+				REGULATOR_MODE_NORMAL) {
+			core->handoff_done = false;
+			d_vpr_h("Skip acquire regulator %s\n", rinfo->name);
+			goto exit;
+		}
+
+		rc = regulator_set_mode(rinfo->regulator,
+				REGULATOR_MODE_NORMAL);
+		if (rc) {
+			/*
+			 * This is somewhat fatal, but nothing we can do
+			 * about it. We can't disable the regulator w/o
+			 * getting it back under s/w control
+			 */
+			d_vpr_e("Failed to acquire regulator control: %s\n",
+				rinfo->name);
+			goto exit;
+		} else {
+			core->handoff_done = false;
+			d_vpr_h("Acquired regulator control from HW: %s\n",
+					rinfo->name);
+
+		}
+
+		if (!regulator_is_enabled(rinfo->regulator)) {
+			d_vpr_e("%s: Regulator is not enabled %s\n",
+				__func__, rinfo->name);
+			__fatal_error(true);
+		}
+	}
+
+exit:
+	return rc;
+}
+
+static int __acquire_regulators(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	struct regulator_info *rinfo;
+
+	venus_hfi_for_each_regulator(core, rinfo)
+		__acquire_regulator(core, rinfo);
+
+	return rc;
+}
+
+static int __hand_off_regulator(struct msm_vidc_core *core,
+	struct regulator_info *rinfo)
+{
+	int rc = 0;
+
+	if (rinfo->has_hw_power_collapse) {
+		if (!rinfo->regulator) {
+			d_vpr_e("%s: invalid regulator\n", __func__);
+			return -EINVAL;
+		}
+
+		rc = regulator_set_mode(rinfo->regulator,
+				REGULATOR_MODE_FAST);
+		if (rc) {
+			d_vpr_e("Failed to hand off regulator control: %s\n",
+				rinfo->name);
+			return rc;
+		} else {
+			core->handoff_done = true;
+			d_vpr_h("Hand off regulator control to HW: %s\n",
+					rinfo->name);
+		}
+
+		if (!regulator_is_enabled(rinfo->regulator)) {
+			d_vpr_e("%s: Regulator is not enabled %s\n",
+				__func__, rinfo->name);
+			__fatal_error(true);
+		}
+	}
+
+	return rc;
+}
+
+static int __hand_off_regulators(struct msm_vidc_core *core)
+{
+	struct regulator_info *rinfo;
+	int rc = 0, c = 0;
+
+	venus_hfi_for_each_regulator(core, rinfo) {
+		rc = __hand_off_regulator(core, rinfo);
+		/*
+		 * If one regulator hand off failed, driver should take
+		 * the control for other regulators back.
+		 */
+		if (rc)
+			goto err_reg_handoff_failed;
+		c++;
+	}
+
+	return rc;
+err_reg_handoff_failed:
+	venus_hfi_for_each_regulator_reverse_continue(core, rinfo, c)
+		__acquire_regulator(core, rinfo);
+
+	return rc;
+}
+
+static int __disable_regulator(struct msm_vidc_core *core, const char *reg_name)
+{
+	int rc = 0;
+	struct regulator_info *rinfo;
+	bool found;
+
+	if (!core || !reg_name) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	found = false;
+	venus_hfi_for_each_regulator(core, rinfo) {
+		if (!rinfo->regulator) {
+			d_vpr_e("%s: invalid regulator %s\n",
+				__func__, rinfo->name);
+			return -EINVAL;
+		}
+		if (strcmp(rinfo->name, reg_name))
+			continue;
+		found = true;
+
+		rc = __acquire_regulator(core, rinfo);
+		if (rc) {
+			d_vpr_e("%s: failed to acquire %s, rc = %d\n",
+				__func__, rinfo->name, rc);
+			/* Bring attention to this issue */
+			WARN_ON(true);
+			return rc;
+		}
+		core->handoff_done = false;
+
+		rc = regulator_disable(rinfo->regulator);
+		if (rc) {
+			d_vpr_e("%s: failed to disable %s, rc = %d\n",
+				__func__, rinfo->name, rc);
+			return rc;
+		}
+		d_vpr_h("%s: disabled regulator %s\n", __func__, rinfo->name);
+		break;
+	}
+	if (!found) {
+		d_vpr_e("%s: regulator %s not found\n", __func__, reg_name);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int __enable_regulator(struct msm_vidc_core *core, const char *reg_name)
+{
+	int rc = 0;
+	struct regulator_info *rinfo;
+	bool found;
+
+	if (!core || !reg_name) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	found = false;
+	venus_hfi_for_each_regulator(core, rinfo) {
+		if (!rinfo->regulator) {
+			d_vpr_e("%s: invalid regulator %s\n",
+				__func__, rinfo->name);
+			return -EINVAL;
+		}
+		if (strcmp(rinfo->name, reg_name))
+			continue;
+		found = true;
+
+		rc = regulator_enable(rinfo->regulator);
+		if (rc) {
+			d_vpr_e("%s: failed to enable %s, rc = %d\n",
+				__func__, rinfo->name, rc);
+			return rc;
+		}
+		if (!regulator_is_enabled(rinfo->regulator)) {
+			d_vpr_e("%s: regulator %s not enabled\n",
+				__func__, rinfo->name);
+			regulator_disable(rinfo->regulator);
+			return -EINVAL;
+		}
+		d_vpr_h("%s: enabled regulator %s\n", __func__, rinfo->name);
+		break;
+	}
+	if (!found) {
+		d_vpr_e("%s: regulator %s not found\n", __func__, reg_name);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int __set_registers(struct msm_vidc_core *core)
+{
+	struct reg_set *reg_set;
+	int i, rc = 0;
+
+	if (!core || !core->dt) {
+		d_vpr_e("core resources null, cannot set registers\n");
+		return -EINVAL;
+	}
+
+	reg_set = &core->dt->reg_set;
+	for (i = 0; i < reg_set->count; i++) {
+		rc = __write_register_masked(core, reg_set->reg_tbl[i].reg,
+					     reg_set->reg_tbl[i].value,
+					     reg_set->reg_tbl[i].mask);
+		if (rc)
+			return rc;
+	}
+
+	return rc;
+}
+
+#ifdef CONFIG_MSM_MMRM
+static void __deregister_mmrm(struct msm_vidc_core *core)
+{
+	struct clock_info *cl;
+
+	if (!core || !core->capabilities) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return;
+	}
+
+	if (!core->capabilities[MMRM].value) {
+		d_vpr_h("%s: MMRM not supported\n", __func__);
+		return;
+	}
+
+	venus_hfi_for_each_clock(core, cl) {
+		if (cl->has_scaling && cl->mmrm_client) {
+			mmrm_client_deregister(cl->mmrm_client);
+			cl->mmrm_client = NULL;
+		}
+	}
+}
+#else
+static void __deregister_mmrm(struct msm_vidc_core *core)
+{
+}
+#endif
+
+#ifdef CONFIG_MSM_MMRM
+static int __register_mmrm(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	struct clock_info *cl;
+
+	if (!core ||!core->capabilities) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!core->capabilities[MMRM].value) {
+		d_vpr_h("%s: MMRM not supported\n", __func__);
+		return 0;
+	}
+
+	venus_hfi_for_each_clock(core, cl) {
+		struct mmrm_client_desc desc;
+		char *name = (char *)desc.client_info.desc.name;
+
+		// TODO: set notifier data vals
+		struct mmrm_client_notifier_data notifier_data = {
+			MMRM_CLIENT_RESOURCE_VALUE_CHANGE,
+			{{0, 0}},
+			NULL};
+
+		// TODO: add callback fn
+		desc.notifier_callback_fn = NULL;
+
+		if (!cl->has_scaling)
+			continue;
+
+		if (IS_ERR_OR_NULL(cl->clk)) {
+			d_vpr_e("%s: Invalid clock: %s\n", __func__, cl->name);
+			rc = PTR_ERR(cl->clk) ? PTR_ERR(cl->clk) : -EINVAL;
+			goto err_register_mmrm;
+		}
+
+		desc.client_type = MMRM_CLIENT_CLOCK;
+		desc.client_info.desc.client_domain = MMRM_CLIENT_DOMAIN_VIDEO;
+		desc.client_info.desc.client_id = cl->clk_id;
+		strlcpy(name, cl->name, sizeof(desc.client_info.desc.name));
+		desc.client_info.desc.clk = cl->clk;
+		desc.priority = MMRM_CLIENT_PRIOR_LOW;
+		desc.pvt_data = notifier_data.pvt_data;
+
+		d_vpr_h("%s: domain(%d) cid(%d) name(%s) clk(%pK)\n",
+			__func__,
+			desc.client_info.desc.client_domain,
+			desc.client_info.desc.client_id,
+			desc.client_info.desc.name,
+			desc.client_info.desc.clk);
+
+		d_vpr_h("%s: type(%d) pri(%d) pvt(%pK) notifier(%pK)\n",
+			__func__,
+			desc.client_type,
+			desc.priority,
+			desc.pvt_data,
+			desc.notifier_callback_fn);
+
+		cl->mmrm_client = mmrm_client_register(&desc);
+		if (!cl->mmrm_client) {
+			d_vpr_e("%s: Failed to register clk(%s): %d\n",
+				__func__, cl->name, rc);
+			rc = -EINVAL;
+			goto err_register_mmrm;
+		}
+	}
+
+	return 0;
+
+err_register_mmrm:
+	__deregister_mmrm(core);
+	return rc;
+}
+#else
+static int __register_mmrm(struct msm_vidc_core *core)
+{
+	return 0;
+}
+#endif
+
+static void __deinit_regulators(struct msm_vidc_core *core)
+{
+	struct regulator_info *rinfo = NULL;
+
+	venus_hfi_for_each_regulator_reverse(core, rinfo) {
+		if (rinfo->regulator) {
+			regulator_put(rinfo->regulator);
+			rinfo->regulator = NULL;
+		}
+	}
+}
+
+static int __init_regulators(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	struct regulator_info *rinfo = NULL;
+
+	venus_hfi_for_each_regulator(core, rinfo) {
+		rinfo->regulator = regulator_get(&core->pdev->dev, rinfo->name);
+		if (IS_ERR_OR_NULL(rinfo->regulator)) {
+			rc = PTR_ERR(rinfo->regulator) ?
+				PTR_ERR(rinfo->regulator) : -EBADHANDLE;
+			d_vpr_e("Failed to get regulator: %s\n", rinfo->name);
+			rinfo->regulator = NULL;
+			goto err_reg_get;
+		}
+	}
+
+	return 0;
+
+err_reg_get:
+	__deinit_regulators(core);
+	return rc;
+}
+
+static void __deinit_subcaches(struct msm_vidc_core *core)
+{
+	struct subcache_info *sinfo = NULL;
+
+	if (!core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		goto exit;
+	}
+
+	if (!is_sys_cache_present(core))
+		goto exit;
+
+	venus_hfi_for_each_subcache_reverse(core, sinfo) {
+		if (sinfo->subcache) {
+			d_vpr_h("deinit_subcaches: %s\n", sinfo->name);
+			llcc_slice_putd(sinfo->subcache);
+			sinfo->subcache = NULL;
+		}
+	}
+
+exit:
+	return;
+}
+
+static int __init_subcaches(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	struct subcache_info *sinfo = NULL;
+
+	if (!core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!is_sys_cache_present(core))
+		return 0;
+
+	venus_hfi_for_each_subcache(core, sinfo) {
+		if (!strcmp("vidsc0", sinfo->name)) {
+			sinfo->subcache = llcc_slice_getd(LLCC_VIDSC0);
+		} else if (!strcmp("vidsc1", sinfo->name)) {
+			sinfo->subcache = llcc_slice_getd(LLCC_VIDSC1);
+		} else if (!strcmp("vidscfw", sinfo->name)) {
+			sinfo->subcache = llcc_slice_getd(LLCC_VIDFW);
+		}else if (!strcmp("vidvsp", sinfo->name)) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0))
+			sinfo->subcache = llcc_slice_getd(LLCC_VIDVSP);
+#endif
+		} else {
+			d_vpr_e("Invalid subcache name %s\n",
+					sinfo->name);
+		}
+		if (IS_ERR_OR_NULL(sinfo->subcache)) {
+			rc = PTR_ERR(sinfo->subcache) ?
+				PTR_ERR(sinfo->subcache) : -EBADHANDLE;
+			d_vpr_e("init_subcaches: invalid subcache: %s rc %d\n",
+				sinfo->name, rc);
+			sinfo->subcache = NULL;
+			goto err_subcache_get;
+		}
+		d_vpr_h("init_subcaches: %s\n", sinfo->name);
+	}
+
+	return 0;
+
+err_subcache_get:
+	__deinit_subcaches(core);
+	return rc;
+}
+
+static int __disable_subcaches(struct msm_vidc_core *core)
+{
+	struct subcache_info *sinfo;
+	int rc = 0;
+
+	if (msm_vidc_syscache_disable || !is_sys_cache_present(core))
+		return 0;
+
+	/* De-activate subcaches */
+	venus_hfi_for_each_subcache_reverse(core, sinfo) {
+		if (sinfo->isactive) {
+			d_vpr_h("De-activate subcache %s\n",
+				sinfo->name);
+			rc = llcc_slice_deactivate(sinfo->subcache);
+			if (rc) {
+				d_vpr_e("Failed to de-activate %s: %d\n",
+					sinfo->name, rc);
+			}
+			sinfo->isactive = false;
+		}
+	}
+
+	return 0;
+}
+
+static int __enable_subcaches(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	u32 c = 0;
+	struct subcache_info *sinfo;
+
+	if (msm_vidc_syscache_disable || !is_sys_cache_present(core))
+		return 0;
+
+	/* Activate subcaches */
+	venus_hfi_for_each_subcache(core, sinfo) {
+		rc = llcc_slice_activate(sinfo->subcache);
+		if (rc) {
+			d_vpr_e("Failed to activate %s: %d\n", sinfo->name, rc);
+			__fatal_error(true);
+			goto err_activate_fail;
+		}
+		sinfo->isactive = true;
+		d_vpr_h("Activated subcache %s\n", sinfo->name);
+		c++;
+	}
+
+	d_vpr_h("Activated %d Subcaches to Venus\n", c);
+
+	return 0;
+
+err_activate_fail:
+	__disable_subcaches(core);
+	return rc;
+}
+
+static int llcc_enable(struct msm_vidc_core *core, bool enable)
+{
+	int ret;
+
+	if (enable)
+		ret = __enable_subcaches(core);
+	else
+		ret = __disable_subcaches(core);
+
+	return ret;
+}
+
+static int __vote_bandwidth(struct bus_info *bus, unsigned long bw_kbps)
+{
+	int rc = 0;
+
+	if (!bus->path) {
+		d_vpr_e("%s: invalid bus\n", __func__);
+		return -EINVAL;
+	}
+
+	d_vpr_p("Voting bus %s to ab %lu kBps\n", bus->name, bw_kbps);
+
+	rc = icc_set_bw(bus->path, bw_kbps, 0);
+	if (rc)
+		d_vpr_e("Failed voting bus %s to ab %lu, rc=%d\n",
+			bus->name, bw_kbps, rc);
+
+	return rc;
+}
+
+static int __unvote_buses(struct msm_vidc_core *core)
+{
+	int rc = 0;
+	struct bus_info *bus = NULL;
+
+	if (!core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	core->power.bw_ddr = 0;
+	core->power.bw_llcc = 0;
+
+	venus_hfi_for_each_bus(core, bus) {
+		rc = __vote_bandwidth(bus, 0);
+		if (rc)
+			goto err_unknown_device;
+	}
+
+err_unknown_device:
+	return rc;
+}
+
+static int __vote_buses(struct msm_vidc_core *core,
+			unsigned long bw_ddr, unsigned long bw_llcc)
+{
+	int rc = 0;
+	struct bus_info *bus = NULL;
+	unsigned long bw_kbps = 0, bw_prev = 0;
+	enum vidc_bus_type type;
+
+	if (!core) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	venus_hfi_for_each_bus(core, bus) {
+		if (bus && bus->path) {
+			type = get_type_frm_name(bus->name);
+
+			if (type == DDR) {
+				bw_kbps = bw_ddr;
+				bw_prev = core->power.bw_ddr;
+			} else if (type == LLCC) {
+				bw_kbps = bw_llcc;
+				bw_prev = core->power.bw_llcc;
+			} else {
+				bw_kbps = bus->range[1];
+				bw_prev = core->power.bw_ddr ?
+						bw_kbps : 0;
+			}
+
+			/* ensure freq is within limits */
+			bw_kbps = clamp_t(typeof(bw_kbps), bw_kbps,
+						 bus->range[0], bus->range[1]);
+
+			if (TRIVIAL_BW_CHANGE(bw_kbps, bw_prev) && bw_prev) {
+				d_vpr_l("Skip voting bus %s to %lu kBps\n",
+					bus->name, bw_kbps);
+				continue;
+			}
+
+			rc = __vote_bandwidth(bus, bw_kbps);
+
+			if (type == DDR)
+				core->power.bw_ddr = bw_kbps;
+			else if (type == LLCC)
+				core->power.bw_llcc = bw_kbps;
+		} else {
+			d_vpr_e("No BUS to Vote\n");
+		}
+	}
+
+	return rc;
+}
+
+static int set_bw(struct msm_vidc_core *core, unsigned long bw_ddr,
+		  unsigned long bw_llcc)
+{
+	if (!bw_ddr && !bw_llcc)
+		return __unvote_buses(core);
+
+	return __vote_buses(core, bw_ddr, bw_llcc);
+}
+
+#ifdef CONFIG_MSM_MMRM
+static int __set_clk_rate(struct msm_vidc_core *core, struct clock_info *cl,
+			  u64 rate)
+{
+	int rc = 0;
+	struct mmrm_client_data client_data;
+	struct mmrm_client *client;
+
+	/* not registered */
+	if (!core || !cl || !core->capabilities) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (core->capabilities[MMRM].value && !cl->mmrm_client) {
+		d_vpr_e("%s: invalid mmrm client\n", __func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * This conversion is necessary since we are scaling clock values based on
+	 * the branch clock. However, mmrm driver expects source clock to be registered
+	 * and used for scaling.
+	 * TODO: Remove this scaling if using source clock instead of branch clock.
+	 */
+	rate = rate * MSM_VIDC_CLOCK_SOURCE_SCALING_RATIO;
+
+	/* bail early if requested clk rate is not changed */
+	if (rate == cl->prev)
+		return 0;
+
+	d_vpr_p("Scaling clock %s to %llu, prev %llu\n", cl->name, rate, cl->prev);
+
+	if (core->capabilities[MMRM].value) {
+		/* set clock rate to mmrm driver */
+		client = cl->mmrm_client;
+		memset(&client_data, 0, sizeof(client_data));
+		client_data.num_hw_blocks = 1;
+		rc = mmrm_client_set_value(client, &client_data, rate);
+		if (rc) {
+			d_vpr_e("%s: Failed to set mmrm clock rate %llu %s: %d\n",
+				__func__, rate, cl->name, rc);
+			return rc;
+		}
+	} else {
+		/* set clock rate to clock driver */
+		rc = clk_set_rate(cl->clk, rate);
+		if (rc) {
+			d_vpr_e("%s: Failed to set clock rate %llu %s: %d\n",
+				__func__, rate, cl->name, rc);
+			return rc;
+		}
+	}
+	cl->prev = rate;
+	return rc;
+}
+#else
+static int __set_clk_rate(struct msm_vidc_core *core, struct clock_info *cl,
+			  u64 rate)
+{
+	int rc = 0;
+
+	/* not registered */
+	if (!core || !cl || !core->capabilities) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * This conversion is necessary since we are scaling clock values based on
+	 * the branch clock. However, mmrm driver expects source clock to be registered
+	 * and used for scaling.
+	 * TODO: Remove this scaling if using source clock instead of branch clock.
+	 */
+	rate = rate * MSM_VIDC_CLOCK_SOURCE_SCALING_RATIO;
+
+	/* bail early if requested clk rate is not changed */
+	if (rate == cl->prev)
+		return 0;
+
+	d_vpr_p("Scaling clock %s to %llu, prev %llu\n", cl->name, rate, cl->prev);
+
+	rc = clk_set_rate(cl->clk, rate);
+	if (rc) {
+		d_vpr_e("%s: Failed to set clock rate %llu %s: %d\n",
+			__func__, rate, cl->name, rc);
+		return rc;
+	}
+
+	cl->prev = rate;
+
+	return rc;
+}
+#endif
+
+static int __set_clocks(struct msm_vidc_core *core, u64 freq)
+{
+	int rc = 0;
+	struct clock_info *cl;
+
+	venus_hfi_for_each_clock(core, cl) {
+		if (cl->has_scaling) {
+			rc = __set_clk_rate(core, cl, freq);
+			if (rc)
+				return rc;
+		}
+	}
+
+	return 0;
+}
+
+static int __disable_unprepare_clock(struct msm_vidc_core *core,
+				     const char *clk_name)
+{
+	int rc = 0;
+	struct clock_info *cl;
+	bool found;
+
+	if (!core || !clk_name) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	found = false;
+	venus_hfi_for_each_clock(core, cl) {
+		if (!cl->clk) {
+			d_vpr_e("%s: invalid clock %s\n", __func__, cl->name);
+			return -EINVAL;
+		}
+		if (strcmp(cl->name, clk_name))
+			continue;
+		found = true;
+		clk_disable_unprepare(cl->clk);
+		if (cl->has_scaling)
+			__set_clk_rate(core, cl, 0);
+		cl->prev = 0;
+		d_vpr_h("%s: clock %s disable unprepared\n", __func__, cl->name);
+		break;
+	}
+	if (!found) {
+		d_vpr_e("%s: clock %s not found\n", __func__, clk_name);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int __prepare_enable_clock(struct msm_vidc_core *core,
+				  const char *clk_name)
+{
+	int rc = 0;
+	struct clock_info *cl;
+	bool found;
+	u64 rate = 0;
+
+	if (!core || !clk_name) {
+		d_vpr_e("%s: invalid params\n", __func__);
+		return -EINVAL;
+	}
+
+	found = false;
+	venus_hfi_for_each_clock(core, cl) {
+		if (!cl->clk) {
+			d_vpr_e("%s: invalid clock\n", __func__);
+			return -EINVAL;
+		}
+		if (strcmp(cl->name, clk_name))
+			continue;
+		found = true;
+		/*
+		 * For the clocks we control, set the rate prior to preparing
+		 * them.  Since we don't really have a load at this point, scale
+		 * it to the lowest frequency possible
+		 */
+		if (cl->has_scaling) {
+			rate = clk_round_rate(cl->clk, 0);
+			/**
+			 * source clock is already multipled with scaling ratio and __set_clk_rate
+			 * attempts to multiply again. So divide scaling ratio before calling
+			 * __set_clk_rate.
+			 */
+			rate = rate / MSM_VIDC_CLOCK_SOURCE_SCALING_RATIO;
+			__set_clk_rate(core, cl, rate);
+		}
+
+		rc = clk_prepare_enable(cl->clk);
+		if (rc) {
+			d_vpr_e("%s: failed to enable clock %s\n",
+				__func__, cl->name);
+			return rc;
+		}
+		if (!__clk_is_enabled(cl->clk)) {
+			d_vpr_e("%s: clock %s not enabled\n",
+				__func__, cl->name);
+			clk_disable_unprepare(cl->clk);
+			if (cl->has_scaling)
+				__set_clk_rate(core, cl, 0);
+			return -EINVAL;
+		}
+		d_vpr_h("%s: clock %s prepare enabled\n", __func__, cl->name);
+		break;
+	}
+	if (!found) {
+		d_vpr_e("%s: clock %s not found\n", __func__, clk_name);
+		return -EINVAL;
+	}
+
+	return rc;
+}
+
+static int __init_resources(struct msm_vidc_core *core)
+{
+	int i, rc = 0;
+
+	rc = __init_regulators(core);
+	if (rc) {
+		d_vpr_e("Failed to get all regulators\n");
+		return -ENODEV;
+	}
+
+	rc = __init_clocks(core);
+	if (rc) {
+		d_vpr_e("Failed to init clocks\n");
+		rc = -ENODEV;
+		goto err_init_clocks;
+	}
+
+	rc = __register_mmrm(core);
+	if (rc) {
+		d_vpr_e("Failed to register mmrm\n");
+		rc = -ENODEV;
+		goto err_init_mmrm;
+	}
+
+	for (i = 0; i < core->dt->reset_set.count; i++) {
+		rc = __handle_reset_clk(core, i, INIT);
+		if (rc) {
+			d_vpr_e("Failed to init reset clocks\n");
+			rc = -ENODEV;
+			goto err_init_reset_clk;
+		}
+	}
+
+	rc = __init_bus(core);
+	if (rc) {
+		d_vpr_e("Failed to init bus: %d\n", rc);
+		goto err_init_bus;
+	}
+
+	rc = __init_subcaches(core);
+	if (rc)
+		d_vpr_e("Failed to init subcaches: %d\n", rc);
+
+	return rc;
+
+err_init_reset_clk:
+err_init_bus:
+	__deregister_mmrm(core);
+err_init_mmrm:
+	__deinit_clocks(core);
+err_init_clocks:
+	__deinit_regulators(core);
+	return rc;
+}
+
+static void __deinit_resources(struct msm_vidc_core *core)
+{
+	__deinit_subcaches(core);
+	__deinit_bus(core);
+	__deregister_mmrm(core);
+	__deinit_clocks(core);
+	__deinit_regulators(core);
+}
+
+static const struct msm_vidc_resources_ops res_ops = {
+	.get = __init_resources,
+	.put = __deinit_resources,
+	.reset_bridge = __reset_ahb2axi_bridge,
+	.gdsc_on = __enable_regulator,
+	.gdsc_off = __disable_regulator,
+	.gdsc_hw_ctrl = __hand_off_regulators,
+	.gdsc_sw_ctrl = __acquire_regulators,
+	.llcc = llcc_enable,
+	.set_bw = set_bw,
+	.set_clks = __set_clocks,
+	.clk_enable = __prepare_enable_clock,
+	.clk_disable = __disable_unprepare_clock,
+	.set_regs = __set_registers,
+};
+
+const struct msm_vidc_resources_ops *get_resources_ops(void)
+{
+	return &res_ops;
+}

Diferenças do arquivo suprimidas por serem muito extensas
+ 12 - 874
driver/vidc/src/venus_hfi.c


Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff