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

Commit e7e9258e authored by Maheshwar Ajja's avatar Maheshwar Ajja
Browse files

msm: vidc: Remove power lock dependency on power collapse feature



The "clk_pwr_lock" lock is not necessary for power collapse feature.
The clock gating ON and OFF functions are also unused and hence
removed the lock and clock gating functions and made the necessary
changes for proper video and power collapse feature functionality.
Do not set the receive request on debug queue when it is empty
which will make video hardware to generate interrupt unnecessarily
when debug message is available, interrupt is necessary when there
is a response message available in the message queue.

Change-Id: I2ec1d9411ddfe1040acde73861d30c34c69abae6
Signed-off-by: default avatarMaheshwar Ajja <majja@codeaurora.org>
parent bb8d2c21
Loading
Loading
Loading
Loading
+147 −182
Original line number Diff line number Diff line
@@ -76,13 +76,13 @@ struct tzbsp_video_set_state_req {
	u32 spare; /*reserved for future, should be zero*/
};

static void venus_hfi_pm_hndlr(struct work_struct *work);
static DECLARE_DELAYED_WORK(venus_hfi_pm_work, venus_hfi_pm_hndlr);
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_power_on(
	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);

@@ -286,8 +286,6 @@ static int venus_hfi_write_queue(void *info, u8 *packet, u32 *rx_req_is_set)
	}

	packet_size_in_words = (*(u32 *)packet) >> 2;
	dprintk(VIDC_DBG, "Packet_size in words: %d\n", packet_size_in_words);

	if (packet_size_in_words == 0) {
		dprintk(VIDC_ERR, "Zero packet size\n");
		return -ENODATA;
@@ -298,7 +296,6 @@ static int venus_hfi_write_queue(void *info, u8 *packet, u32 *rx_req_is_set)
	empty_space = (queue->qhdr_write_idx >=  read_idx) ?
		(queue->qhdr_q_size - (queue->qhdr_write_idx -  read_idx)) :
		(read_idx - queue->qhdr_write_idx);
	dprintk(VIDC_DBG, "Empty_space: %d\n", empty_space);
	if (empty_space <= packet_size_in_words) {
		queue->qhdr_tx_req =  1;
		dprintk(VIDC_ERR, "Insufficient size (%d) to write (%d)\n",
@@ -311,7 +308,6 @@ static int venus_hfi_write_queue(void *info, u8 *packet, u32 *rx_req_is_set)
	new_write_idx = (queue->qhdr_write_idx + packet_size_in_words);
	write_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
		(queue->qhdr_write_idx << 2));
	dprintk(VIDC_DBG, "Write Ptr: %d\n", new_write_idx);
	if (new_write_idx < queue->qhdr_q_size) {
		memcpy(write_ptr, packet, packet_size_in_words << 2);
	} else {
@@ -405,6 +401,7 @@ static int venus_hfi_read_queue(void *info, u8 *packet, u32 *pb_tx_req_is_set)
	struct hfi_queue_header *queue;
	u32 packet_size_in_words, new_read_idx;
	u32 *read_ptr;
	u32 receive_request = 0;
	struct vidc_iface_q_info *qinfo;
	int rc = 0;

@@ -428,23 +425,37 @@ static int venus_hfi_read_queue(void *info, u8 *packet, u32 *pb_tx_req_is_set)
		return -ENOMEM;
	}

	/*
	 * Do not set receive request for debug queue, if set,
	 * Venus generates interrupt for debug messages even
	 * when there is no response message available.
	 * In general debug queue will not become full as it
	 * is being emptied out for every interrupt from Venus.
	 * Venus will anyway generates interrupt if it is full.
	 */
	if (queue->qhdr_type & HFI_Q_ID_CTRL_TO_HOST_MSG_Q)
		receive_request = 1;

	if (queue->qhdr_read_idx == queue->qhdr_write_idx) {
		queue->qhdr_rx_req = 1;
		queue->qhdr_rx_req = receive_request;
		*pb_tx_req_is_set = 0;
		return -EPERM;
		dprintk(VIDC_DBG,
			"%s queue is empty, rx_req = %u, tx_req = %u, read_idx = %u\n",
			receive_request ? "message" : "debug",
			queue->qhdr_rx_req, queue->qhdr_tx_req,
			queue->qhdr_read_idx);
		return -ENODATA;
	}

	read_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
				(queue->qhdr_read_idx << 2));
	packet_size_in_words = (*read_ptr) >> 2;
	dprintk(VIDC_DBG, "packet_size_in_words: %d\n", packet_size_in_words);
	if (packet_size_in_words == 0) {
		dprintk(VIDC_ERR, "Zero packet size\n");
		return -ENODATA;
	}

	new_read_idx = queue->qhdr_read_idx + packet_size_in_words;
	dprintk(VIDC_DBG, "Read Ptr: %d\n", new_read_idx);
	if (((packet_size_in_words << 2) <= VIDC_IFACEQ_VAR_HUGE_PKT_SIZE)
			&& queue->qhdr_read_idx <= queue->qhdr_q_size) {
		if (new_read_idx < queue->qhdr_q_size) {
@@ -473,13 +484,15 @@ static int venus_hfi_read_queue(void *info, u8 *packet, u32 *pb_tx_req_is_set)
	if (queue->qhdr_read_idx != queue->qhdr_write_idx)
		queue->qhdr_rx_req = 0;
	else
		queue->qhdr_rx_req = 1;
		queue->qhdr_rx_req = receive_request;

	*pb_tx_req_is_set = (1 == queue->qhdr_tx_req) ? 1 : 0;

	if (msm_vidc_debug & VIDC_PKT) {
		dprintk(VIDC_PKT, "%s: %p\n", __func__, qinfo);
		venus_hfi_dump_packet(packet);
	}

	return rc;
}

@@ -530,7 +543,10 @@ static void venus_hfi_free(struct venus_hfi_device *dev, struct msm_smem *mem)
		dprintk(VIDC_ERR, "invalid param %p %p\n", dev, mem);
		return;
	}
	venus_hfi_power_enable(dev);

	if (venus_hfi_power_on(dev))
		dprintk(VIDC_ERR, "%s: Power on failed\n", __func__);

	msm_smem_free(dev->hal_client, mem);
}

@@ -574,6 +590,9 @@ static int venus_hfi_read_register(struct venus_hfi_device *device, u32 reg)

	rc = readl_relaxed(base_addr + reg);
	rmb();
	dprintk(VIDC_DBG, "Base addr: 0x%p, read from: 0x%x, value: 0x%x...\n",
		base_addr, reg, rc);

	return rc;
}

@@ -893,9 +912,7 @@ static int venus_hfi_iface_cmdq_write(struct venus_hfi_device *device,
		return -EINVAL;
	}
	mutex_lock(&device->write_lock);
	mutex_lock(&device->clk_pwr_lock);
	result = venus_hfi_iface_cmdq_write_nolock(device, pkt);
	mutex_unlock(&device->clk_pwr_lock);
	mutex_unlock(&device->write_lock);
	return result;
}
@@ -1171,8 +1188,6 @@ static inline int venus_hfi_clk_enable(struct venus_hfi_device *device)
		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
		return -EINVAL;
	}
	WARN(!mutex_is_locked(&device->clk_pwr_lock),
				"Clock/power lock must be acquired");
	if (device->clk_state == ENABLED_PREPARED) {
		dprintk(VIDC_DBG, "Clocks already enabled\n");
		return 0;
@@ -1218,8 +1233,6 @@ static inline void venus_hfi_clk_disable(struct venus_hfi_device *device)
		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
		return;
	}
	WARN(!mutex_is_locked(&device->clk_pwr_lock),
			"Clock/power lock must be acquired");
	if (device->clk_state != ENABLED_PREPARED) {
		dprintk(VIDC_DBG, "Clocks already disabled\n");
		return;
@@ -1260,12 +1273,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");
		rc = -EIO;
		goto err_clk_gating_off;
	if (venus_hfi_power_enable(device)) {
		dprintk(VIDC_ERR, "%s: Failed to enable power\n", __func__);
		return 0;
	}

	/* Halt AXI and AXI OCMEM VBIF Access */
	reg = venus_hfi_read_register(device, VENUS_VBIF_AXI_HALT_CTRL0);
	reg |= VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ;
@@ -1279,8 +1291,7 @@ 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;
}

@@ -1293,9 +1304,10 @@ static inline int venus_hfi_power_off(struct venus_hfi_device *device)
	}
	if (!device->power_enabled) {
		dprintk(VIDC_DBG, "Power already disabled\n");
		goto already_disabled;
		return 0;
	}

	dprintk(VIDC_DBG, "Entering power collapse\n");
	/*Temporarily enable clocks to make TZ call.*/
	rc = venus_hfi_clk_enable(device);
	if (rc) {
@@ -1319,8 +1331,8 @@ static inline int venus_hfi_power_off(struct venus_hfi_device *device)
	venus_hfi_unvote_buses(device);

	device->power_enabled = false;
	dprintk(VIDC_INFO, "entering power collapse\n");
already_disabled:
	dprintk(VIDC_INFO, "Venus power collapsed\n");

	return rc;
}

@@ -1331,7 +1343,10 @@ static inline int venus_hfi_power_on(struct venus_hfi_device *device)
		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
		return -EINVAL;
	}
	if (device->power_enabled)
		return 0;

	dprintk(VIDC_DBG, "Resuming from power collapse\n");
	rc = venus_hfi_vote_buses(device, device->bus_load,
			device->res->bus_set.count, 0);
	if (rc) {
@@ -1394,6 +1409,12 @@ static inline int venus_hfi_power_on(struct venus_hfi_device *device)
		goto err_reset_core;
	}

	/*
	 * set the flag here to skip venus_hfi_power_on() which is
	 * being called again via __alloc_ocmem() if ocmem is enabled
	 */
	device->power_enabled = true;

	/*
	 * write_lock is already acquired at this point, so to avoid
	 * recursive lock in cmdq_write function, call nolock version
@@ -1405,8 +1426,8 @@ 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 = true;
	dprintk(VIDC_INFO, "resuming from power collapse\n");

	dprintk(VIDC_INFO, "Resumed from power collapse\n");
	return rc;
err_alloc_ocmem:
err_reset_core:
@@ -1420,6 +1441,8 @@ err_iommu_attach:
err_enable_gdsc:
	venus_hfi_unvote_buses(device);
err_vote_buses:
	device->power_enabled = false;
	dprintk(VIDC_ERR, "Failed to resume from power collapse\n");
	return rc;
}

@@ -1431,58 +1454,12 @@ static int venus_hfi_power_enable(void *dev)
		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
		return -EINVAL;
	}

	mutex_lock(&device->clk_pwr_lock);
	if (!device->power_enabled) {
	mutex_lock(&device->write_lock);
	rc = venus_hfi_power_on(device);
		if (rc) {
			dprintk(VIDC_ERR, "Failed venus power on");
			goto fail_power_on;
		}
	}
	rc = venus_hfi_clk_gating_off(device);
	if (rc)
		dprintk(VIDC_ERR, "%s : Clock enable failed\n", __func__);
		dprintk(VIDC_ERR, "%s: Failed to enable power\n", __func__);
	mutex_unlock(&device->write_lock);

fail_power_on:
	mutex_unlock(&device->clk_pwr_lock);
	return rc;
}

static void venus_hfi_pm_hndlr(struct work_struct *work);
static DECLARE_DELAYED_WORK(venus_hfi_pm_work, venus_hfi_pm_hndlr);

static inline int venus_hfi_clk_gating_off(struct venus_hfi_device *device)
{
	int rc = 0;
	if (!device) {
		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
		return -EINVAL;
	}
	if (device->clk_state == ENABLED_PREPARED) {
		dprintk(VIDC_DBG, "Clocks are already enabled\n");
		goto already_enabled;
	}
	if (!device->power_enabled) {
		/*This will enable clocks as well*/
		rc = venus_hfi_power_on(device);
		if (rc) {
			dprintk(VIDC_ERR, "Failed venus power on");
			goto fail_clk_power_on;
		}
	} else {
		rc = venus_hfi_clk_enable(device);
		if (rc) {
			dprintk(VIDC_ERR, "Failed venus clock enable\n");
			goto fail_clk_power_on;
		}
		venus_hfi_write_register(device,
				VIDC_WRAPPER_INTR_MASK,
				VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK);
	}
already_enabled:
	device->clk_state = ENABLED_PREPARED;
fail_clk_power_on:
	return rc;
}

@@ -1520,6 +1497,7 @@ static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device,
{
	u32 rx_req_is_set = 0;
	struct vidc_iface_q_info *q_info;
	struct vidc_hal_cmd_pkt_hdr *cmd_packet;
	int result = -EPERM;

	if (!device || !pkt) {
@@ -1534,6 +1512,9 @@ static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device,
		goto err_q_null;
	}

	cmd_packet = (struct vidc_hal_cmd_pkt_hdr *)pkt;
	device->last_packet_type = cmd_packet->packet_type;

	q_info = &device->iface_queues[VIDC_IFACEQ_CMDQ_IDX];
	if (!q_info) {
		dprintk(VIDC_ERR, "cannot write to shared Q's\n");
@@ -1548,16 +1529,12 @@ static int venus_hfi_iface_cmdq_write_nolock(struct venus_hfi_device *device,

	venus_hfi_sim_modify_cmd_packet((u8 *)pkt, device);
	if (!venus_hfi_write_queue(q_info, (u8 *)pkt, &rx_req_is_set)) {
		WARN(!mutex_is_locked(&device->clk_pwr_lock),
					"Clock/power lock must be acquired");
		result = venus_hfi_clk_gating_off(device);
		if (result) {
			dprintk(VIDC_ERR, "%s : Clock enable failed\n",
					__func__);

		if (venus_hfi_power_on(device)) {
			dprintk(VIDC_ERR, "%s: Power on failed\n", __func__);
			goto err_q_write;
		}
		result = venus_hfi_scale_clocks(device, device->clk_load);
		if (result) {
		if (venus_hfi_scale_clocks(device, device->clk_load)) {
			dprintk(VIDC_ERR, "Clock scaling failed\n");
			goto err_q_write;
		}
@@ -1614,25 +1591,14 @@ static int venus_hfi_iface_msgq_read(struct venus_hfi_device *device, void *pkt)
	q_info = &device->iface_queues[VIDC_IFACEQ_MSGQ_IDX];
	if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
		venus_hfi_hal_sim_modify_msg_packet((u8 *)pkt, device);
		mutex_lock(&device->clk_pwr_lock);
		rc = venus_hfi_clk_gating_off(device);
		if (rc) {
			dprintk(VIDC_ERR,
					"%s : Clock enable failed\n", __func__);
			mutex_unlock(&device->clk_pwr_lock);
			goto read_error;
		}
		if (tx_req_is_set)
			venus_hfi_write_register(
				device, VIDC_CPU_IC_SOFTINT,
				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT);
		rc = 0;
		mutex_unlock(&device->clk_pwr_lock);
	} else {
		dprintk(VIDC_INFO, "venus_hfi_iface_msgq_read:queue_empty\n");
	} else
		rc = -ENODATA;
	}
read_error:

read_error_null:
	mutex_unlock(&device->read_lock);
	return rc;
@@ -1662,25 +1628,14 @@ static int venus_hfi_iface_dbgq_read(struct venus_hfi_device *device, void *pkt)
	}
	q_info = &device->iface_queues[VIDC_IFACEQ_DBGQ_IDX];
	if (!venus_hfi_read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) {
		mutex_lock(&device->clk_pwr_lock);
		rc = venus_hfi_clk_gating_off(device);
		if (rc) {
			dprintk(VIDC_ERR,
				"%s : Clock enable failed\n", __func__);
			mutex_unlock(&device->clk_pwr_lock);
			goto dbg_error;
		}
		if (tx_req_is_set)
			venus_hfi_write_register(
				device, VIDC_CPU_IC_SOFTINT,
				1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT);
		rc = 0;
		mutex_unlock(&device->clk_pwr_lock);
	} else {
		dprintk(VIDC_INFO, "venus_hfi_iface_dbgq_read:queue_empty\n");
	} else
		rc = -ENODATA;
	}
dbg_error:

dbg_error_null:
	mutex_unlock(&device->read_lock);
	return rc;
@@ -1927,6 +1882,11 @@ static int venus_hfi_interface_queues_init(struct venus_hfi_device *dev)
	q_hdr = iface_q->q_hdr;
	q_hdr->qhdr_start_addr = (u32)iface_q->q_array.align_device_addr;
	q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q;
	/*
	 * Set receive request to zero on debug queue as there is no
	 * need of interrupt from video hardware for debug messages
	 */
	q_hdr->qhdr_rx_req = 0;
	if ((ion_phys_addr_t)q_hdr->qhdr_start_addr !=
		iface_q->q_array.align_device_addr) {
		dprintk(VIDC_ERR, "Invalid DBGQ device address (0x%pa)",
@@ -2147,7 +2107,7 @@ err_core_init:
static int venus_hfi_core_release(void *device)
{
	struct venus_hfi_device *dev;
	int rc = 0;

	if (device) {
		dev = device;
	} else {
@@ -2156,19 +2116,15 @@ static int venus_hfi_core_release(void *device)
	}

	if (dev->hal_client) {
		mutex_lock(&dev->clk_pwr_lock);
		rc = venus_hfi_clk_gating_off(device);
		if (rc) {
		if (venus_hfi_power_enable(device)) {
			dprintk(VIDC_ERR,
				"%s : Clock enable failed\n", __func__);
			mutex_unlock(&dev->clk_pwr_lock);
				"%s: Power enable failed\n", __func__);
			return -EIO;
		}
		venus_hfi_write_register(dev, VIDC_CPU_CS_SCIACMDARG3, 0);
		if (!(dev->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
			disable_irq_nosync(dev->hal_data->irq);
		dev->intr_status = 0;
		mutex_unlock(&dev->clk_pwr_lock);
	}
	venus_hfi_set_state(dev, VENUS_STATE_DEINIT);

@@ -2207,44 +2163,13 @@ static int venus_hfi_get_q_size(struct venus_hfi_device *dev,
	return rc;
}

static inline void venus_hfi_clk_gating_on(struct venus_hfi_device *device)
{
	if (!device) {
		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
		return;
	}
	if (device->clk_state != ENABLED_PREPARED) {
		dprintk(VIDC_DBG, "Clocks are already disabled\n");
		goto already_disabled;
	}
	/*SYS Idle should be last message so mask any further interrupts
	 * until clocks are enabled again.*/
	if (!venus_hfi_get_q_size(device, VIDC_IFACEQ_MSGQ_IDX)) {
		venus_hfi_write_register(device,
				VIDC_WRAPPER_INTR_MASK,
				VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK |
				VIDC_WRAPPER_INTR_MASK_A2HCPU_BMSK);
	}
	venus_hfi_clk_disable(device);
already_disabled:
	device->clk_state = DISABLED_PREPARED;
}

static void venus_hfi_core_clear_interrupt(struct venus_hfi_device *device)
{
	u32 intr_status = 0;
	int rc = 0;

	if (!device->callback)
	if (!device) {
		dprintk(VIDC_ERR, "%s: NULL device\n", __func__);
		return;

	mutex_lock(&device->write_lock);
	mutex_lock(&device->clk_pwr_lock);
	rc = venus_hfi_clk_gating_off(device);
	if (rc) {
		dprintk(VIDC_ERR,
			"%s : Clock enable failed\n", __func__);
		goto err_clk_gating_off;
	}

	intr_status = venus_hfi_read_register(
@@ -2270,9 +2195,6 @@ static void venus_hfi_core_clear_interrupt(struct venus_hfi_device *device)
	venus_hfi_write_register(device, VIDC_CPU_CS_A2HSOFTINTCLR, 1);
	venus_hfi_write_register(device, VIDC_WRAPPER_INTR_CLEAR, intr_status);
	dprintk(VIDC_DBG, "Cleared WRAPPER/A2H interrupt\n");
err_clk_gating_off:
	mutex_unlock(&device->clk_pwr_lock);
	mutex_unlock(&device->write_lock);
}

static int venus_hfi_core_ping(void *device)
@@ -2947,14 +2869,19 @@ err_pc_prep:
static void venus_hfi_pm_hndlr(struct work_struct *work)
{
	int rc = 0;
	u32 ctrl_status = 0;
	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) {
		dprintk(VIDC_ERR, "%s: NULL device\n", __func__);
		return;
	}
	if (!device->power_enabled) {
		dprintk(VIDC_DBG, "Power already disabled\n");
		goto clks_enabled;
		dprintk(VIDC_DBG, "%s: Power already disabled\n",
				__func__);
		return;
	}
	mutex_unlock(&device->clk_pwr_lock);
	dprintk(VIDC_DBG, "Prepare for power collapse\n");

	rc = venus_hfi_unset_free_ocmem(device);
	if (rc) {
@@ -2971,12 +2898,56 @@ static void venus_hfi_pm_hndlr(struct work_struct *work)
		return;
	}

	mutex_lock(&device->clk_pwr_lock);
	mutex_lock(&device->write_lock);

	if (device->last_packet_type != HFI_CMD_SYS_PC_PREP) {
		dprintk(VIDC_DBG,
			"Last command (0x%x) is not PC_PREP cmd\n",
			device->last_packet_type);
		goto skip_power_off;
	}

	if (venus_hfi_get_q_size(device, VIDC_IFACEQ_MSGQ_IDX) ||
		venus_hfi_get_q_size(device, VIDC_IFACEQ_CMDQ_IDX)) {
		dprintk(VIDC_DBG, "Cmd/msg queues are not empty\n");
		goto skip_power_off;
	}

	ctrl_status = venus_hfi_read_register(device, VIDC_CPU_CS_SCIACMDARG0);
	if (!(ctrl_status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY)) {
		dprintk(VIDC_DBG,
			"Venus is not ready for power collapse (0x%x)\n",
			ctrl_status);
		goto skip_power_off;
	}

	rc = venus_hfi_power_off(device);
	if (rc)
		dprintk(VIDC_ERR, "Failed venus power off\n");
clks_enabled:
	mutex_unlock(&device->clk_pwr_lock);

	/* Cancel pending delayed works if any */
	cancel_delayed_work(&venus_hfi_pm_work);

	mutex_unlock(&device->write_lock);
	return;

skip_power_off:

	/* Reset PC_READY bit as power_off is skipped, if set by Venus */
	ctrl_status = venus_hfi_read_register(device, VIDC_CPU_CS_SCIACMDARG0);
	if (ctrl_status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY) {
		ctrl_status &= ~(VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY);
		venus_hfi_write_register(device, VIDC_CPU_CS_SCIACMDARG0,
			ctrl_status);
	}

	/* Cancel pending delayed works if any */
	cancel_delayed_work(&venus_hfi_pm_work);
	dprintk(VIDC_WARN, "Power off skipped (0x%x, 0x%x)\n",
		device->last_packet_type, ctrl_status);

	mutex_unlock(&device->write_lock);
	return;
}

static void venus_hfi_process_msg_event_notify(
@@ -3090,6 +3061,10 @@ static void venus_hfi_core_work_handler(struct work_struct *work)
				device);
		return;
	}
	if (venus_hfi_power_enable(device)) {
		dprintk(VIDC_ERR, "%s: Power enable failed\n", __func__);
		return;
	}
	if (device->res->sw_power_collapsible) {
		dprintk(VIDC_DBG, "Cancel and queue delayed work again.\n");
		cancel_delayed_work(&venus_hfi_pm_work);
@@ -3249,7 +3224,6 @@ static inline void venus_hfi_disable_unprepare_clks(
		dprintk(VIDC_ERR, "Invalid params: %p\n", device);
		return;
	}
	WARN_ON(!mutex_is_locked(&device->clk_pwr_lock));
	venus_hfi_for_each_clock(device, cl) {
		if (device->clk_state == DISABLED_PREPARED) {
			dprintk(VIDC_DBG,
@@ -3258,6 +3232,8 @@ static inline void venus_hfi_disable_unprepare_clks(
			clk_unprepare(cl->clk);
		} else {
			usleep(100);
			dprintk(VIDC_DBG, "Clock: %s disable and unprepare\n",
				cl->name);
			clk_disable_unprepare(cl->clk);
		}
	}
@@ -3272,7 +3248,6 @@ static inline int venus_hfi_prepare_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));

	if (device->clk_state == ENABLED_PREPARED) {
		dprintk(VIDC_DBG, "Clocks already prepared and enabled\n");
@@ -3286,7 +3261,7 @@ static inline int venus_hfi_prepare_enable_clks(struct venus_hfi_device *device)
			goto fail_clk_enable;
		}

		dprintk(VIDC_DBG, "Clock: %s enabled\n", cl->name);
		dprintk(VIDC_DBG, "Clock: %s prepared and enabled\n", cl->name);
	}

	device->clk_state = ENABLED_PREPARED;
@@ -3297,10 +3272,11 @@ fail_clk_enable:
		if (cl_fail == cl)
			break;
		usleep(100);
		dprintk(VIDC_ERR, "Clock: %s disable and unprepare\n",
			cl->name);
		clk_disable_unprepare(cl->clk);
	}
	device->clk_state = DISABLED_UNPREPARED;
	mutex_unlock(&device->clk_pwr_lock);

	return rc;
}
@@ -3786,11 +3762,9 @@ static int venus_hfi_load_fw(void *dev)
		goto fail_iommu_attach;
	}

	mutex_lock(&device->clk_pwr_lock);
	rc = venus_hfi_enable_regulators(device);
	if (rc) {
		dprintk(VIDC_ERR, "Failed to enable GDSC %d\n", rc);
		mutex_unlock(&device->clk_pwr_lock);
		goto fail_enable_gdsc;
	}

@@ -3803,7 +3777,6 @@ static int venus_hfi_load_fw(void *dev)
		if (IS_ERR_OR_NULL(device->resources.fw.cookie)) {
			dprintk(VIDC_ERR, "Failed to download firmware\n");
			rc = -ENOMEM;
			mutex_unlock(&device->clk_pwr_lock);
			goto fail_load_fw;
		}
	}
@@ -3812,7 +3785,6 @@ static int venus_hfi_load_fw(void *dev)
	/* Clocks can be enabled only after pil_get since
	 * gdsc is turned-on in pil_get*/
	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;
@@ -3831,18 +3803,14 @@ static int venus_hfi_load_fw(void *dev)
	trace_msm_v4l2_vidc_fw_load_end("msm_v4l2_vidc venus_fw load end");
	return rc;
fail_protect_mem:
	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);
fail_load_fw:
	mutex_lock(&device->clk_pwr_lock);
	device->resources.fw.cookie = NULL;
	venus_hfi_disable_regulators(device);
	device->power_enabled = false;
	mutex_unlock(&device->clk_pwr_lock);
fail_enable_gdsc:
	venus_hfi_iommu_detach(device);
fail_iommu_attach:
@@ -3870,11 +3838,9 @@ static void venus_hfi_unload_fw(void *dev)
		 */
		if (venus_hfi_halt_axi(device))
			dprintk(VIDC_WARN, "Failed to halt AXI\n");
		mutex_lock(&device->clk_pwr_lock);
		venus_hfi_disable_unprepare_clks(device);
		venus_hfi_disable_regulators(device);
		device->power_enabled = false;
		mutex_unlock(&device->clk_pwr_lock);
		device->resources.fw.cookie = NULL;
	}
}
@@ -4031,7 +3997,6 @@ static void *venus_hfi_add_device(u32 device_id,
	mutex_init(&hdevice->read_lock);
	mutex_init(&hdevice->write_lock);
	mutex_init(&hdevice->session_lock);
	mutex_init(&hdevice->clk_pwr_lock);

	if (hal_ctxt.dev_count == 0)
		INIT_LIST_HEAD(&hal_ctxt.dev_head);
+1 −0
Original line number Diff line number Diff line
@@ -176,6 +176,7 @@ struct venus_hfi_device {
	u32 intr_status;
	u32 device_id;
	u32 clk_load;
	u32 last_packet_type;
	struct vidc_bus_vote_data *bus_load;
	enum clock_state clk_state;
	bool power_enabled;
+5 −0
Original line number Diff line number Diff line
@@ -807,6 +807,11 @@ struct hfi_mvc_buffer_layout_descp_type {
#define HFI_TEST_SSR_SW_DIV_BY_ZERO	0x2
#define HFI_TEST_SSR_HW_WDOG_IRQ	0x3

struct vidc_hal_cmd_pkt_hdr {
	u32 size;
	u32 packet_type;
};

struct vidc_hal_msg_pkt_hdr {
	u32 size;
	u32 packet;