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

Commit 30631b6c 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: unprepare clocks during power collapse"

parents a9bf778c 0ccf3cc6
Loading
Loading
Loading
Loading
+56 −39
Original line number Diff line number Diff line
@@ -90,6 +90,12 @@ static int venus_hfi_power_enable(void *dev);

static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device);

static inline int venus_hfi_prepare_enable_clks(
	struct venus_hfi_device *device);

static inline void venus_hfi_disable_unprepare_clks(
	struct venus_hfi_device *device);

static void venus_hfi_dump_packet(u8 *packet)
{
	u32 c = 0, packet_size = *(u32 *)packet;
@@ -531,7 +537,7 @@ static void venus_hfi_write_register(
		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
		return;
	}
	if (!device->clocks_enabled) {
	if (device->clk_state != ENABLED_PREPARED) {
		dprintk(VIDC_WARN,
			"HFI Write register failed : Clocks are OFF\n");
		return;
@@ -553,7 +559,7 @@ static int venus_hfi_read_register(struct venus_hfi_device *device, u32 reg)
		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
		return -EINVAL;
	}
	if (!device->clocks_enabled) {
	if (device->clk_state != ENABLED_PREPARED) {
		dprintk(VIDC_WARN,
			"HFI Read register failed : Clocks are OFF\n");
		return -EINVAL;
@@ -1151,7 +1157,7 @@ static inline int venus_hfi_clk_enable(struct venus_hfi_device *device)
	}
	WARN(!mutex_is_locked(&device->clk_pwr_lock),
				"Clock/power lock must be acquired");
	if (device->clocks_enabled) {
	if (device->clk_state == ENABLED_PREPARED) {
		dprintk(VIDC_DBG, "Clocks already enabled\n");
		return 0;
	}
@@ -1170,8 +1176,7 @@ static inline int venus_hfi_clk_enable(struct venus_hfi_device *device)

		++i;
	}

	device->clocks_enabled = 1;
	device->clk_state = ENABLED_PREPARED;
	return 0;
fail_clk_enable:
	venus_hfi_for_each_clock(device, cl) {
@@ -1185,6 +1190,7 @@ fail_clk_enable:

		--i;
	}
	device->clk_state = DISABLED_PREPARED;
	return rc;
}

@@ -1198,7 +1204,7 @@ static inline void venus_hfi_clk_disable(struct venus_hfi_device *device)
	}
	WARN(!mutex_is_locked(&device->clk_pwr_lock),
			"Clock/power lock must be acquired");
	if (!device->clocks_enabled) {
	if (device->clk_state != ENABLED_PREPARED) {
		dprintk(VIDC_DBG, "Clocks already disabled\n");
		return;
	}
@@ -1224,7 +1230,7 @@ static inline void venus_hfi_clk_disable(struct venus_hfi_device *device)
		}
	}

	device->clocks_enabled = 0;
	device->clk_state = DISABLED_PREPARED;
}

static DECLARE_COMPLETION(pc_prep_done);
@@ -1238,9 +1244,11 @@ static int venus_hfi_halt_axi(struct venus_hfi_device *device)
		dprintk(VIDC_ERR, "Invalid input: %p\n", device);
		return -EINVAL;
	}
	mutex_lock(&device->clk_pwr_lock);
	if (venus_hfi_clk_gating_off(device)) {
		dprintk(VIDC_ERR, "Failed to turn off clk gating\n");
		return -EIO;
		rc = -EIO;
		goto err_clk_gating_off;
	}
	/* Halt AXI and AXI OCMEM VBIF Access */
	reg = venus_hfi_read_register(device, VENUS_VBIF_AXI_HALT_CTRL0);
@@ -1255,6 +1263,8 @@ static int venus_hfi_halt_axi(struct venus_hfi_device *device)
			VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US);
	if (rc)
		dprintk(VIDC_WARN, "AXI bus port halt timeout\n");
err_clk_gating_off:
	mutex_unlock(&device->clk_pwr_lock);
	return rc;
}

@@ -1282,7 +1292,7 @@ static inline int venus_hfi_power_off(struct venus_hfi_device *device)
		venus_hfi_clk_disable(device);
		return rc;
	}
	venus_hfi_clk_disable(device);
	venus_hfi_disable_unprepare_clks(device);
	venus_hfi_iommu_detach(device);
	rc = regulator_disable(venus_hfi_get_regulator(device, "venus"));
	if (rc) {
@@ -1292,7 +1302,7 @@ static inline int venus_hfi_power_off(struct venus_hfi_device *device)

	venus_hfi_unvote_buses(device);

	device->power_enabled = 0;
	device->power_enabled = false;
	dprintk(VIDC_INFO, "entering power collapse\n");
already_disabled:
	return rc;
@@ -1325,7 +1335,11 @@ static inline int venus_hfi_power_on(struct venus_hfi_device *device)
		goto err_iommu_attach;
	}

	if (device->clk_state == DISABLED_UNPREPARED)
		rc = venus_hfi_prepare_enable_clks(device);
	else if (device->clk_state == DISABLED_PREPARED)
		rc = venus_hfi_clk_enable(device);

	if (rc) {
		dprintk(VIDC_ERR, "Failed to enable clocks\n");
		goto err_enable_clk;
@@ -1375,7 +1389,7 @@ static inline int venus_hfi_power_on(struct venus_hfi_device *device)
		dprintk(VIDC_ERR, "Failed to allocate OCMEM");
		goto err_alloc_ocmem;
	}
	device->power_enabled = 1;
	device->power_enabled = true;
	dprintk(VIDC_INFO, "resuming from power collapse\n");
	return rc;
err_alloc_ocmem:
@@ -1419,7 +1433,7 @@ static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device)
		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
		return -EINVAL;
	}
	if (device->clocks_enabled) {
	if (device->clk_state == ENABLED_PREPARED) {
		dprintk(VIDC_DBG, "Clocks are already enabled\n");
		goto already_enabled;
	}
@@ -1442,7 +1456,7 @@ static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device)
				VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK);
	}
already_enabled:
	device->clocks_enabled = 1;
	device->clk_state = ENABLED_PREPARED;
fail_clk_power_on:
	return rc;
}
@@ -2158,7 +2172,7 @@ static inline void venus_hfi_clk_gating_on(struct venus_hfi_device *device)
		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
		return;
	}
	if (!device->clocks_enabled) {
	if (device->clk_state != ENABLED_PREPARED) {
		dprintk(VIDC_DBG, "Clocks are already disabled\n");
		goto already_disabled;
	}
@@ -2175,7 +2189,7 @@ static inline void venus_hfi_clk_gating_on(struct venus_hfi_device *device)
			msecs_to_jiffies(msm_vidc_pwr_collapse_delay)))
		dprintk(VIDC_DBG, "PM work already scheduled\n");
already_disabled:
	device->clocks_enabled = 0;
	device->clk_state = DISABLED_PREPARED;
}

static void venus_hfi_core_clear_interrupt(struct venus_hfi_device *device)
@@ -2895,10 +2909,10 @@ static void venus_hfi_pm_hndlr(struct work_struct *work)
	struct venus_hfi_device *device = list_first_entry(
			&hal_ctxt.dev_head, struct venus_hfi_device, list);
	mutex_lock(&device->clk_pwr_lock);
	if (device->clocks_enabled || !device->power_enabled) {
	if (device->clk_state == ENABLED_PREPARED || !device->power_enabled) {
		dprintk(VIDC_DBG,
				"Clocks status: %d, Power status: %d, ignore power off\n",
				device->clocks_enabled, device->power_enabled);
				device->clk_state, device->power_enabled);
		goto clks_enabled;
	}
	mutex_unlock(&device->clk_pwr_lock);
@@ -2919,7 +2933,7 @@ static void venus_hfi_pm_hndlr(struct work_struct *work)
	}

	mutex_lock(&device->clk_pwr_lock);
	if (device->clocks_enabled) {
	if (device->clk_state == ENABLED_PREPARED) {
		dprintk(VIDC_ERR,
				"Clocks are still enabled after PC_PREP_DONE, ignore power off\n");
		goto clks_enabled;
@@ -3221,17 +3235,18 @@ static inline void venus_hfi_deinit_clocks(struct venus_hfi_device *device)
		clk_put(cl->clk);
}

static inline void venus_hfi_disable_clks(struct venus_hfi_device *device)
static inline void venus_hfi_disable_unprepare_clks(
	struct venus_hfi_device *device)
{
	struct clock_info *cl;
	if (!device) {
		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
		return;
	}

	mutex_lock(&device->clk_pwr_lock);
	WARN_ON(!mutex_is_locked(&device->clk_pwr_lock));
	venus_hfi_for_each_clock(device, cl) {
		if (!device->clocks_enabled && cl->has_sw_power_collapse) {
		if (device->clk_state == DISABLED_PREPARED &&
				cl->has_sw_power_collapse) {
			dprintk(VIDC_DBG,
				"Omitting clk_disable of %s in %s as it's already disabled\n",
				cl->name, __func__);
@@ -3241,12 +3256,10 @@ static inline void venus_hfi_disable_clks(struct venus_hfi_device *device)
			clk_disable_unprepare(cl->clk);
		}
	}

	device->clocks_enabled = 0;
	mutex_unlock(&device->clk_pwr_lock);
	device->clk_state = DISABLED_UNPREPARED;
}

static inline int venus_hfi_enable_clks(struct venus_hfi_device *device)
static inline int venus_hfi_prepare_enable_clks(struct venus_hfi_device *device)
{
	struct clock_info *cl = NULL, *cl_fail = NULL;
	int rc = 0;
@@ -3254,8 +3267,12 @@ static inline int venus_hfi_enable_clks(struct venus_hfi_device *device)
		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
		return -EINVAL;
	}
	WARN_ON(!mutex_is_locked(&device->clk_pwr_lock));

	mutex_lock(&device->clk_pwr_lock);
	if (device->clk_state == ENABLED_PREPARED) {
		dprintk(VIDC_DBG, "Clocks already prepared and enabled\n");
		return 0;
	}
	venus_hfi_for_each_clock(device, cl) {
		rc = clk_prepare_enable(cl->clk);
		if (rc) {
@@ -3267,9 +3284,7 @@ static inline int venus_hfi_enable_clks(struct venus_hfi_device *device)
		dprintk(VIDC_DBG, "Clock: %s enabled\n", cl->name);
	}

	device->clocks_enabled = 1;
	mutex_unlock(&device->clk_pwr_lock);

	device->clk_state = ENABLED_PREPARED;
	return rc;

fail_clk_enable:
@@ -3279,6 +3294,7 @@ fail_clk_enable:
		usleep(100);
		clk_disable_unprepare(cl->clk);
	}
	device->clk_state = DISABLED_UNPREPARED;
	mutex_unlock(&device->clk_pwr_lock);

	return rc;
@@ -3781,17 +3797,16 @@ static int venus_hfi_load_fw(void *dev)
			goto fail_load_fw;
		}
	}
	device->power_enabled = 1;
	mutex_unlock(&device->clk_pwr_lock);
	device->power_enabled = true;

	/* Clocks can be enabled only after pil_get since
	 * gdsc is turned-on in pil_get*/
	rc = venus_hfi_enable_clks(device);
	rc = venus_hfi_prepare_enable_clks(device);
	mutex_unlock(&device->clk_pwr_lock);
	if (rc) {
		dprintk(VIDC_ERR, "Failed to enable clocks: %d\n", rc);
		goto fail_enable_clks;
	}

	/* Hand off control of regulators to h/w _after_ enabling clocks */
	venus_hfi_enable_hw_power_collapse(device);

@@ -3805,7 +3820,9 @@ static int venus_hfi_load_fw(void *dev)

	return rc;
fail_protect_mem:
	venus_hfi_disable_clks(device);
	mutex_lock(&device->clk_pwr_lock);
	venus_hfi_disable_unprepare_clks(device);
	mutex_unlock(&device->clk_pwr_lock);
fail_enable_clks:
	if (device->resources.fw.cookie)
		subsystem_put(device->resources.fw.cookie);
@@ -3813,7 +3830,7 @@ fail_load_fw:
	mutex_lock(&device->clk_pwr_lock);
	device->resources.fw.cookie = NULL;
	venus_hfi_disable_regulators(device);
	device->power_enabled = 0;
	device->power_enabled = false;
	mutex_unlock(&device->clk_pwr_lock);
fail_enable_gdsc:
	venus_hfi_iommu_detach(device);
@@ -3841,10 +3858,10 @@ static void venus_hfi_unload_fw(void *dev)
		 */
		if (venus_hfi_halt_axi(device))
			dprintk(VIDC_WARN, "Failed to halt AXI\n");
		venus_hfi_disable_clks(device);
		mutex_lock(&device->clk_pwr_lock);
		venus_hfi_disable_unprepare_clks(device);
		venus_hfi_disable_regulators(device);
		device->power_enabled = 0;
		device->power_enabled = false;
		mutex_unlock(&device->clk_pwr_lock);
		device->resources.fw.cookie = NULL;
	}
+8 −2
Original line number Diff line number Diff line
@@ -122,6 +122,12 @@ enum bus_index {
	BUS_IDX_MAX
};

enum clock_state {
	DISABLED_UNPREPARED,
	ENABLED_PREPARED,
	DISABLED_PREPARED
};

struct vidc_mem_addr {
	ion_phys_addr_t align_device_addr;
	u8 *align_virtual_addr;
@@ -171,8 +177,8 @@ struct venus_hfi_device {
	u32 device_id;
	u32 clk_load;
	struct vidc_bus_vote_data *bus_load;
	u32 clocks_enabled;
	u32 power_enabled;
	enum clock_state clk_state;
	bool power_enabled;
	struct mutex read_lock;
	struct mutex write_lock;
	struct mutex clk_pwr_lock;