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

Commit 6f6d0b12 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: Remove power lock dependency on power collapse feature"

parents 155a408e e7e9258e
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;
}

@@ -1294,9 +1305,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) {
@@ -1327,8 +1339,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;
}

@@ -1340,7 +1352,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) {
@@ -1410,6 +1425,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
@@ -1421,8 +1442,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:
@@ -1436,6 +1457,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;
}

@@ -1447,58 +1470,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;
}

@@ -1536,6 +1513,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) {
@@ -1550,6 +1528,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");
@@ -1564,16 +1545,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;
		}
@@ -1630,25 +1607,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;
@@ -1678,25 +1644,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;
@@ -1943,6 +1898,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)",
@@ -2163,7 +2123,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 {
@@ -2172,19 +2132,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);

@@ -2223,44 +2179,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(
@@ -2286,9 +2211,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)
@@ -2963,14 +2885,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) {
@@ -2987,12 +2914,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(
@@ -3106,6 +3077,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);
@@ -3265,7 +3240,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,
@@ -3274,6 +3248,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);
		}
	}
@@ -3288,7 +3264,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");
@@ -3302,7 +3277,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;
@@ -3313,10 +3288,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;
}
@@ -3802,11 +3778,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;
	}

@@ -3819,7 +3793,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;
		}
	}
@@ -3828,7 +3801,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;
@@ -3847,18 +3819,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:
@@ -3886,11 +3854,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;
	}
}
@@ -4047,7 +4013,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;