summaryrefslogtreecommitdiff
path: root/drivers/media/platform/qcom/venus/hfi_venus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/qcom/venus/hfi_venus.c')
-rw-r--r--drivers/media/platform/qcom/venus/hfi_venus.c453
1 files changed, 306 insertions, 147 deletions
diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c
index 5c1e5b4f767a..d3da35f67fd5 100644
--- a/drivers/media/platform/qcom/venus/hfi_venus.c
+++ b/drivers/media/platform/qcom/venus/hfi_venus.c
@@ -1,16 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* Copyright (C) 2017 Linaro Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/delay.h>
@@ -139,8 +130,7 @@ struct venus_hfi_device {
};
static bool venus_pkt_debug;
-static int venus_fw_debug = HFI_DEBUG_MSG_ERROR | HFI_DEBUG_MSG_FATAL;
-static bool venus_sys_idle_indicator;
+int venus_fw_debug = HFI_DEBUG_MSG_ERROR | HFI_DEBUG_MSG_FATAL;
static bool venus_fw_low_power_mode = true;
static int venus_hw_rsp_timeout = 1000;
static bool venus_fw_coverage;
@@ -197,6 +187,9 @@ static int venus_write_queue(struct venus_hfi_device *hdev,
/* ensure rd/wr indices's are read from memory */
rmb();
+ if (qsize > IFACEQ_QUEUE_SIZE / 4)
+ return -EINVAL;
+
if (wr_idx >= rd_idx)
empty_space = qsize - (wr_idx - rd_idx);
else
@@ -215,6 +208,11 @@ static int venus_write_queue(struct venus_hfi_device *hdev,
new_wr_idx = wr_idx + dwords;
wr_ptr = (u32 *)(queue->qmem.kva + (wr_idx << 2));
+
+ if (wr_ptr < (u32 *)queue->qmem.kva ||
+ wr_ptr > (u32 *)(queue->qmem.kva + queue->qmem.size - sizeof(*wr_ptr)))
+ return -EINVAL;
+
if (new_wr_idx < qsize) {
memcpy(wr_ptr, packet, dwords << 2);
} else {
@@ -241,6 +239,7 @@ static int venus_write_queue(struct venus_hfi_device *hdev,
static int venus_read_queue(struct venus_hfi_device *hdev,
struct iface_queue *queue, void *pkt, u32 *tx_req)
{
+ struct hfi_pkt_hdr *pkt_hdr = NULL;
struct hfi_queue_header *qhdr;
u32 dwords, new_rd_idx;
u32 rd_idx, wr_idx, type, qsize;
@@ -260,6 +259,9 @@ static int venus_read_queue(struct venus_hfi_device *hdev,
wr_idx = qhdr->write_idx;
qsize = qhdr->q_size;
+ if (qsize > IFACEQ_QUEUE_SIZE / 4)
+ return -EINVAL;
+
/* make sure data is valid before using it */
rmb();
@@ -282,6 +284,11 @@ static int venus_read_queue(struct venus_hfi_device *hdev,
}
rd_ptr = (u32 *)(queue->qmem.kva + (rd_idx << 2));
+
+ if (rd_ptr < (u32 *)queue->qmem.kva ||
+ rd_ptr > (u32 *)(queue->qmem.kva + queue->qmem.size - sizeof(*rd_ptr)))
+ return -EINVAL;
+
dwords = *rd_ptr >> 2;
if (!dwords)
return -EINVAL;
@@ -298,6 +305,9 @@ static int venus_read_queue(struct venus_hfi_device *hdev,
memcpy(pkt, rd_ptr, len);
memcpy(pkt + len, queue->qmem.kva, new_rd_idx << 2);
}
+ pkt_hdr = (struct hfi_pkt_hdr *)(pkt);
+ if ((pkt_hdr->size >> 2) != dwords)
+ return -EINVAL;
} else {
/* bad packet received, dropping */
new_rd_idx = qhdr->write_idx;
@@ -354,16 +364,6 @@ static void venus_free(struct venus_hfi_device *hdev, struct mem_desc *mem)
dma_free_attrs(dev, mem->size, mem->kva, mem->da, mem->attrs);
}
-static void venus_writel(struct venus_hfi_device *hdev, u32 reg, u32 value)
-{
- writel(value, hdev->core->base + reg);
-}
-
-static u32 venus_readl(struct venus_hfi_device *hdev, u32 reg)
-{
- return readl(hdev->core->base + reg);
-}
-
static void venus_set_registers(struct venus_hfi_device *hdev)
{
const struct venus_resources *res = hdev->core->res;
@@ -372,16 +372,24 @@ static void venus_set_registers(struct venus_hfi_device *hdev)
unsigned int i;
for (i = 0; i < count; i++)
- venus_writel(hdev, tbl[i].reg, tbl[i].value);
+ writel(tbl[i].value, hdev->core->base + tbl[i].reg);
}
static void venus_soft_int(struct venus_hfi_device *hdev)
{
- venus_writel(hdev, CPU_IC_SOFTINT, BIT(CPU_IC_SOFTINT_H2A_SHIFT));
+ void __iomem *cpu_ic_base = hdev->core->cpu_ic_base;
+ u32 clear_bit;
+
+ if (IS_V6(hdev->core) || (IS_V4(hdev->core) && is_lite(hdev->core)))
+ clear_bit = BIT(CPU_IC_SOFTINT_H2A_SHIFT_V6);
+ else
+ clear_bit = BIT(CPU_IC_SOFTINT_H2A_SHIFT);
+
+ writel(clear_bit, cpu_ic_base + CPU_IC_SOFTINT);
}
static int venus_iface_cmdq_write_nolock(struct venus_hfi_device *hdev,
- void *pkt)
+ void *pkt, bool sync)
{
struct device *dev = hdev->core->dev;
struct hfi_pkt_hdr *cmd_packet;
@@ -403,18 +411,29 @@ static int venus_iface_cmdq_write_nolock(struct venus_hfi_device *hdev,
return ret;
}
+ if (sync) {
+ /*
+ * Inform video hardware to raise interrupt for synchronous
+ * commands
+ */
+ queue = &hdev->queues[IFACEQ_MSG_IDX];
+ queue->qhdr->rx_req = 1;
+ /* ensure rx_req is updated in memory */
+ wmb();
+ }
+
if (rx_req)
venus_soft_int(hdev);
return 0;
}
-static int venus_iface_cmdq_write(struct venus_hfi_device *hdev, void *pkt)
+static int venus_iface_cmdq_write(struct venus_hfi_device *hdev, void *pkt, bool sync)
{
int ret;
mutex_lock(&hdev->lock);
- ret = venus_iface_cmdq_write_nolock(hdev, pkt);
+ ret = venus_iface_cmdq_write_nolock(hdev, pkt, sync);
mutex_unlock(&hdev->lock);
return ret;
@@ -437,7 +456,7 @@ static int venus_hfi_core_set_resource(struct venus_core *core, u32 id,
if (ret)
return ret;
- ret = venus_iface_cmdq_write(hdev, pkt);
+ ret = venus_iface_cmdq_write(hdev, pkt, false);
if (ret)
return ret;
@@ -448,16 +467,27 @@ static int venus_boot_core(struct venus_hfi_device *hdev)
{
struct device *dev = hdev->core->dev;
static const unsigned int max_tries = 100;
- u32 ctrl_status = 0;
+ u32 ctrl_status = 0, mask_val = 0;
unsigned int count = 0;
+ void __iomem *cpu_cs_base = hdev->core->cpu_cs_base;
+ void __iomem *wrapper_base = hdev->core->wrapper_base;
int ret = 0;
- venus_writel(hdev, VIDC_CTRL_INIT, BIT(VIDC_CTRL_INIT_CTRL_SHIFT));
- venus_writel(hdev, WRAPPER_INTR_MASK, WRAPPER_INTR_MASK_A2HVCODEC_MASK);
- venus_writel(hdev, CPU_CS_SCIACMDARG3, 1);
+ if (IS_IRIS2(hdev->core) || IS_IRIS2_1(hdev->core)) {
+ mask_val = readl(wrapper_base + WRAPPER_INTR_MASK);
+ mask_val &= ~(WRAPPER_INTR_MASK_A2HWD_BASK_V6 |
+ WRAPPER_INTR_MASK_A2HCPU_MASK);
+ } else {
+ mask_val = WRAPPER_INTR_MASK_A2HVCODEC_MASK;
+ }
+ writel(mask_val, wrapper_base + WRAPPER_INTR_MASK);
+ if (IS_V1(hdev->core))
+ writel(1, cpu_cs_base + CPU_CS_SCIACMDARG3);
+
+ writel(BIT(VIDC_CTRL_INIT_CTRL_SHIFT), cpu_cs_base + VIDC_CTRL_INIT);
while (!ctrl_status && count < max_tries) {
- ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0);
+ ctrl_status = readl(cpu_cs_base + CPU_CS_SCIACMDARG0);
if ((ctrl_status & CPU_CS_SCIACMDARG0_ERROR_STATUS_MASK) == 4) {
dev_err(dev, "invalid setting for UC_REGION\n");
ret = -EINVAL;
@@ -471,22 +501,31 @@ static int venus_boot_core(struct venus_hfi_device *hdev)
if (count >= max_tries)
ret = -ETIMEDOUT;
+ if (IS_IRIS2(hdev->core) || IS_IRIS2_1(hdev->core) || IS_AR50_LITE(hdev->core)) {
+ writel(0x1, cpu_cs_base + CPU_CS_H2XSOFTINTEN_V6);
+
+ if (!IS_AR50_LITE(hdev->core))
+ writel(0x0, cpu_cs_base + CPU_CS_X2RPMH_V6);
+ }
+
return ret;
}
static u32 venus_hwversion(struct venus_hfi_device *hdev)
{
struct device *dev = hdev->core->dev;
- u32 ver = venus_readl(hdev, WRAPPER_HW_VERSION);
+ void __iomem *wrapper_base = hdev->core->wrapper_base;
+ u32 ver;
u32 major, minor, step;
+ ver = readl(wrapper_base + WRAPPER_HW_VERSION);
major = ver & WRAPPER_HW_VERSION_MAJOR_VERSION_MASK;
major = major >> WRAPPER_HW_VERSION_MAJOR_VERSION_SHIFT;
minor = ver & WRAPPER_HW_VERSION_MINOR_VERSION_MASK;
minor = minor >> WRAPPER_HW_VERSION_MINOR_VERSION_SHIFT;
step = ver & WRAPPER_HW_VERSION_STEP_VERSION_MASK;
- dev_dbg(dev, "venus hw version %x.%x.%x\n", major, minor, step);
+ dev_dbg(dev, VDBGL "venus hw version %x.%x.%x\n", major, minor, step);
return major;
}
@@ -494,6 +533,7 @@ static u32 venus_hwversion(struct venus_hfi_device *hdev)
static int venus_run(struct venus_hfi_device *hdev)
{
struct device *dev = hdev->core->dev;
+ void __iomem *cpu_cs_base = hdev->core->cpu_cs_base;
int ret;
/*
@@ -502,12 +542,12 @@ static int venus_run(struct venus_hfi_device *hdev)
*/
venus_set_registers(hdev);
- venus_writel(hdev, UC_REGION_ADDR, hdev->ifaceq_table.da);
- venus_writel(hdev, UC_REGION_SIZE, SHARED_QSIZE);
- venus_writel(hdev, CPU_CS_SCIACMDARG2, hdev->ifaceq_table.da);
- venus_writel(hdev, CPU_CS_SCIACMDARG1, 0x01);
+ writel(hdev->ifaceq_table.da, cpu_cs_base + UC_REGION_ADDR);
+ writel(SHARED_QSIZE, cpu_cs_base + UC_REGION_SIZE);
+ writel(hdev->ifaceq_table.da, cpu_cs_base + CPU_CS_SCIACMDARG2);
+ writel(0x01, cpu_cs_base + CPU_CS_SCIACMDARG1);
if (hdev->sfr.da)
- venus_writel(hdev, SFR_ADDR, hdev->sfr.da);
+ writel(hdev->sfr.da, cpu_cs_base + SFR_ADDR);
ret = venus_boot_core(hdev);
if (ret) {
@@ -522,17 +562,57 @@ static int venus_run(struct venus_hfi_device *hdev)
static int venus_halt_axi(struct venus_hfi_device *hdev)
{
- void __iomem *base = hdev->core->base;
+ void __iomem *wrapper_base = hdev->core->wrapper_base;
+ void __iomem *vbif_base = hdev->core->vbif_base;
+ void __iomem *cpu_cs_base = hdev->core->cpu_cs_base;
+ void __iomem *aon_base = hdev->core->aon_base;
struct device *dev = hdev->core->dev;
u32 val;
+ u32 mask_val;
int ret;
+ if (IS_AR50_LITE(hdev->core))
+ return 0;
+
+ if (IS_IRIS2(hdev->core) || IS_IRIS2_1(hdev->core)) {
+ writel(0x3, cpu_cs_base + CPU_CS_X2RPMH_V6);
+
+ if (IS_IRIS2_1(hdev->core))
+ goto skip_aon_mvp_noc;
+
+ writel(0x1, aon_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL);
+ ret = readl_poll_timeout(aon_base + AON_WRAPPER_MVP_NOC_LPI_STATUS,
+ val,
+ val & BIT(0),
+ POLL_INTERVAL_US,
+ VBIF_AXI_HALT_ACK_TIMEOUT_US);
+ if (ret)
+ return -ETIMEDOUT;
+
+skip_aon_mvp_noc:
+ mask_val = (BIT(2) | BIT(1) | BIT(0));
+ writel(mask_val, wrapper_base + WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_V6);
+
+ writel(0x00, wrapper_base + WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_V6);
+ ret = readl_poll_timeout(wrapper_base + WRAPPER_DEBUG_BRIDGE_LPI_STATUS_V6,
+ val,
+ val == 0,
+ POLL_INTERVAL_US,
+ VBIF_AXI_HALT_ACK_TIMEOUT_US);
+
+ if (ret) {
+ dev_err(dev, "DBLP Release: lpi_status %x\n", val);
+ return -ETIMEDOUT;
+ }
+ return 0;
+ }
+
if (IS_V4(hdev->core)) {
- val = venus_readl(hdev, WRAPPER_CPU_AXI_HALT);
+ val = readl(wrapper_base + WRAPPER_CPU_AXI_HALT);
val |= WRAPPER_CPU_AXI_HALT_HALT;
- venus_writel(hdev, WRAPPER_CPU_AXI_HALT, val);
+ writel(val, wrapper_base + WRAPPER_CPU_AXI_HALT);
- ret = readl_poll_timeout(base + WRAPPER_CPU_AXI_HALT_STATUS,
+ ret = readl_poll_timeout(wrapper_base + WRAPPER_CPU_AXI_HALT_STATUS,
val,
val & WRAPPER_CPU_AXI_HALT_STATUS_IDLE,
POLL_INTERVAL_US,
@@ -546,12 +626,12 @@ static int venus_halt_axi(struct venus_hfi_device *hdev)
}
/* Halt AXI and AXI IMEM VBIF Access */
- val = venus_readl(hdev, VBIF_AXI_HALT_CTRL0);
+ val = readl(vbif_base + VBIF_AXI_HALT_CTRL0);
val |= VBIF_AXI_HALT_CTRL0_HALT_REQ;
- venus_writel(hdev, VBIF_AXI_HALT_CTRL0, val);
+ writel(val, vbif_base + VBIF_AXI_HALT_CTRL0);
/* Request for AXI bus port halt */
- ret = readl_poll_timeout(base + VBIF_AXI_HALT_CTRL1, val,
+ ret = readl_poll_timeout(vbif_base + VBIF_AXI_HALT_CTRL1, val,
val & VBIF_AXI_HALT_CTRL1_HALT_ACK,
POLL_INTERVAL_US,
VBIF_AXI_HALT_ACK_TIMEOUT_US);
@@ -781,34 +861,24 @@ static int venus_sys_set_debug(struct venus_hfi_device *hdev, u32 debug)
{
struct hfi_sys_set_property_pkt *pkt;
u8 packet[IFACEQ_VAR_SMALL_PKT_SIZE];
- int ret;
pkt = (struct hfi_sys_set_property_pkt *)packet;
pkt_sys_debug_config(pkt, HFI_DEBUG_MODE_QUEUE, debug);
- ret = venus_iface_cmdq_write(hdev, pkt);
- if (ret)
- return ret;
-
- return 0;
+ return venus_iface_cmdq_write(hdev, pkt, false);
}
static int venus_sys_set_coverage(struct venus_hfi_device *hdev, u32 mode)
{
struct hfi_sys_set_property_pkt *pkt;
u8 packet[IFACEQ_VAR_SMALL_PKT_SIZE];
- int ret;
pkt = (struct hfi_sys_set_property_pkt *)packet;
pkt_sys_coverage_config(pkt, mode);
- ret = venus_iface_cmdq_write(hdev, pkt);
- if (ret)
- return ret;
-
- return 0;
+ return venus_iface_cmdq_write(hdev, pkt, false);
}
static int venus_sys_set_idle_message(struct venus_hfi_device *hdev,
@@ -816,7 +886,6 @@ static int venus_sys_set_idle_message(struct venus_hfi_device *hdev,
{
struct hfi_sys_set_property_pkt *pkt;
u8 packet[IFACEQ_VAR_SMALL_PKT_SIZE];
- int ret;
if (!enable)
return 0;
@@ -825,11 +894,7 @@ static int venus_sys_set_idle_message(struct venus_hfi_device *hdev,
pkt_sys_idle_indicator(pkt, enable);
- ret = venus_iface_cmdq_write(hdev, pkt);
- if (ret)
- return ret;
-
- return 0;
+ return venus_iface_cmdq_write(hdev, pkt, false);
}
static int venus_sys_set_power_control(struct venus_hfi_device *hdev,
@@ -837,13 +902,26 @@ static int venus_sys_set_power_control(struct venus_hfi_device *hdev,
{
struct hfi_sys_set_property_pkt *pkt;
u8 packet[IFACEQ_VAR_SMALL_PKT_SIZE];
- int ret;
pkt = (struct hfi_sys_set_property_pkt *)packet;
pkt_sys_power_control(pkt, enable);
- ret = venus_iface_cmdq_write(hdev, pkt);
+ return venus_iface_cmdq_write(hdev, pkt, false);
+}
+
+static int venus_sys_set_ubwc_config(struct venus_hfi_device *hdev)
+{
+ struct hfi_sys_set_property_pkt *pkt;
+ u8 packet[IFACEQ_VAR_SMALL_PKT_SIZE];
+ const struct venus_resources *res = hdev->core->res;
+ int ret;
+
+ pkt = (struct hfi_sys_set_property_pkt *)packet;
+
+ pkt_sys_ubwc_config(pkt, res->ubwc_conf);
+
+ ret = venus_iface_cmdq_write(hdev, pkt, false);
if (ret)
return ret;
@@ -868,40 +946,43 @@ static int venus_get_queue_size(struct venus_hfi_device *hdev,
static int venus_sys_set_default_properties(struct venus_hfi_device *hdev)
{
struct device *dev = hdev->core->dev;
+ const struct venus_resources *res = hdev->core->res;
int ret;
ret = venus_sys_set_debug(hdev, venus_fw_debug);
if (ret)
dev_warn(dev, "setting fw debug msg ON failed (%d)\n", ret);
- /*
- * Idle indicator is disabled by default on some 4xx firmware versions,
- * enable it explicitly in order to make suspend functional by checking
- * WFI (wait-for-interrupt) bit.
- */
- if (IS_V4(hdev->core))
- venus_sys_idle_indicator = true;
-
- ret = venus_sys_set_idle_message(hdev, venus_sys_idle_indicator);
- if (ret)
- dev_warn(dev, "setting idle response ON failed (%d)\n", ret);
+ /* HFI_PROPERTY_SYS_IDLE_INDICATOR is not supported beyond 8916 (HFI V1) */
+ if (IS_V1(hdev->core)) {
+ ret = venus_sys_set_idle_message(hdev, false);
+ if (ret)
+ dev_warn(dev, "setting idle response ON failed (%d)\n", ret);
+ }
ret = venus_sys_set_power_control(hdev, venus_fw_low_power_mode);
if (ret)
dev_warn(dev, "setting hw power collapse ON failed (%d)\n",
ret);
+ /* For specific venus core, it is mandatory to set the UBWC configuration */
+ if (res->ubwc_conf) {
+ ret = venus_sys_set_ubwc_config(hdev);
+ if (ret)
+ dev_warn(dev, "setting ubwc config failed (%d)\n", ret);
+ }
+
return ret;
}
-static int venus_session_cmd(struct venus_inst *inst, u32 pkt_type)
+static int venus_session_cmd(struct venus_inst *inst, u32 pkt_type, bool sync)
{
struct venus_hfi_device *hdev = to_hfi_priv(inst->core);
struct hfi_session_pkt pkt;
pkt_session_cmd(&pkt, pkt_type, inst);
- return venus_iface_cmdq_write(hdev, &pkt);
+ return venus_iface_cmdq_write(hdev, &pkt, sync);
}
static void venus_flush_debug_queue(struct venus_hfi_device *hdev)
@@ -915,7 +996,7 @@ static void venus_flush_debug_queue(struct venus_hfi_device *hdev)
if (pkt->hdr.pkt_type != HFI_MSG_SYS_COV) {
struct hfi_msg_sys_debug_pkt *pkt = packet;
- dev_dbg(dev, "%s", pkt->msg_data);
+ dev_dbg(dev, VDBGFW "%s", pkt->msg_data);
}
}
}
@@ -931,7 +1012,7 @@ static int venus_prepare_power_collapse(struct venus_hfi_device *hdev,
pkt_sys_pc_prep(&pkt);
- ret = venus_iface_cmdq_write(hdev, &pkt);
+ ret = venus_iface_cmdq_write(hdev, &pkt, false);
if (ret)
return ret;
@@ -969,18 +1050,26 @@ static void venus_sfr_print(struct venus_hfi_device *hdev)
{
struct device *dev = hdev->core->dev;
struct hfi_sfr *sfr = hdev->sfr.kva;
+ u32 size;
void *p;
if (!sfr)
return;
- p = memchr(sfr->data, '\0', sfr->buf_size);
+ size = sfr->buf_size;
+ if (!size)
+ return;
+
+ if (size > ALIGNED_SFR_SIZE)
+ size = ALIGNED_SFR_SIZE;
+
+ p = memchr(sfr->data, '\0', size);
/*
* SFR isn't guaranteed to be NULL terminated since SYS_ERROR indicates
* that Venus is in the process of crashing.
*/
if (!p)
- sfr->data[sfr->buf_size - 1] = '\0';
+ sfr->data[size - 1] = '\0';
dev_err_ratelimited(dev, "SFR message from FW: %s\n", sfr->data);
}
@@ -995,13 +1084,6 @@ static void venus_process_msg_sys_error(struct venus_hfi_device *hdev,
venus_set_state(hdev, VENUS_STATE_DEINIT);
- /*
- * Once SYS_ERROR received from HW, it is safe to halt the AXI.
- * With SYS_ERROR, Venus FW may have crashed and HW might be
- * active and causing unnecessary transactions. Hence it is
- * safe to stop all AXI transactions from venus subsystem.
- */
- venus_halt_axi(hdev);
venus_sfr_print(hdev);
}
@@ -1018,10 +1100,6 @@ static irqreturn_t venus_isr_thread(struct venus_core *core)
res = hdev->core->res;
pkt = hdev->pkt_buf;
- if (hdev->irq_status & WRAPPER_INTR_STATUS_A2HWD_MASK) {
- venus_sfr_print(hdev);
- hfi_process_watchdog_timeout(core);
- }
while (!venus_iface_msgq_read(hdev, pkt)) {
msg_ret = hfi_process_msg_packet(core, pkt);
@@ -1055,19 +1133,36 @@ static irqreturn_t venus_isr(struct venus_core *core)
{
struct venus_hfi_device *hdev = to_hfi_priv(core);
u32 status;
+ void __iomem *cpu_cs_base;
+ void __iomem *wrapper_base;
if (!hdev)
return IRQ_NONE;
- status = venus_readl(hdev, WRAPPER_INTR_STATUS);
-
- if (status & WRAPPER_INTR_STATUS_A2H_MASK ||
- status & WRAPPER_INTR_STATUS_A2HWD_MASK ||
- status & CPU_CS_SCIACMDARG0_INIT_IDLE_MSG_MASK)
- hdev->irq_status = status;
-
- venus_writel(hdev, CPU_CS_A2HSOFTINTCLR, 1);
- venus_writel(hdev, WRAPPER_INTR_CLEAR, status);
+ cpu_cs_base = hdev->core->cpu_cs_base;
+ wrapper_base = hdev->core->wrapper_base;
+
+ status = readl(wrapper_base + WRAPPER_INTR_STATUS);
+
+ if (IS_AR50_LITE(core)) {
+ if (status & WRAPPER_INTR_STATUS_A2H_MASK ||
+ status & WRAPPER_INTR_STATUS_A2HWD_MASK_V4_LITE ||
+ status & CPU_CS_SCIACMDARG0_INIT_IDLE_MSG_MASK)
+ hdev->irq_status = status;
+ } else if (IS_IRIS2(core) || IS_IRIS2_1(core)) {
+ if (status & WRAPPER_INTR_STATUS_A2H_MASK ||
+ status & WRAPPER_INTR_STATUS_A2HWD_MASK_V6 ||
+ status & CPU_CS_SCIACMDARG0_INIT_IDLE_MSG_MASK)
+ hdev->irq_status = status;
+ } else {
+ if (status & WRAPPER_INTR_STATUS_A2H_MASK ||
+ status & WRAPPER_INTR_STATUS_A2HWD_MASK ||
+ status & CPU_CS_SCIACMDARG0_INIT_IDLE_MSG_MASK)
+ hdev->irq_status = status;
+ }
+ writel(1, cpu_cs_base + CPU_CS_A2HSOFTINTCLR);
+ if (!(IS_IRIS2(core) || IS_IRIS2_1(core) || IS_AR50_LITE(core)))
+ writel(status, wrapper_base + WRAPPER_INTR_CLEAR);
return IRQ_WAKE_THREAD;
}
@@ -1084,13 +1179,13 @@ static int venus_core_init(struct venus_core *core)
venus_set_state(hdev, VENUS_STATE_INIT);
- ret = venus_iface_cmdq_write(hdev, &pkt);
+ ret = venus_iface_cmdq_write(hdev, &pkt, false);
if (ret)
return ret;
pkt_sys_image_version(&version_pkt);
- ret = venus_iface_cmdq_write(hdev, &version_pkt);
+ ret = venus_iface_cmdq_write(hdev, &version_pkt, false);
if (ret)
dev_warn(dev, "failed to send image version pkt to fw\n");
@@ -1112,16 +1207,6 @@ static int venus_core_deinit(struct venus_core *core)
return 0;
}
-static int venus_core_ping(struct venus_core *core, u32 cookie)
-{
- struct venus_hfi_device *hdev = to_hfi_priv(core);
- struct hfi_sys_ping_pkt pkt;
-
- pkt_sys_ping(&pkt, cookie);
-
- return venus_iface_cmdq_write(hdev, &pkt);
-}
-
static int venus_core_trigger_ssr(struct venus_core *core, u32 trigger_type)
{
struct venus_hfi_device *hdev = to_hfi_priv(core);
@@ -1132,7 +1217,7 @@ static int venus_core_trigger_ssr(struct venus_core *core, u32 trigger_type)
if (ret)
return ret;
- return venus_iface_cmdq_write(hdev, &pkt);
+ return venus_iface_cmdq_write(hdev, &pkt, false);
}
static int venus_session_init(struct venus_inst *inst, u32 session_type,
@@ -1142,11 +1227,15 @@ static int venus_session_init(struct venus_inst *inst, u32 session_type,
struct hfi_session_init_pkt pkt;
int ret;
+ ret = venus_sys_set_debug(hdev, venus_fw_debug);
+ if (ret)
+ goto err;
+
ret = pkt_session_init(&pkt, inst, session_type, codec);
if (ret)
goto err;
- ret = venus_iface_cmdq_write(hdev, &pkt);
+ ret = venus_iface_cmdq_write(hdev, &pkt, true);
if (ret)
goto err;
@@ -1167,7 +1256,7 @@ static int venus_session_end(struct venus_inst *inst)
dev_warn(dev, "fw coverage msg ON failed\n");
}
- return venus_session_cmd(inst, HFI_CMD_SYS_SESSION_END);
+ return venus_session_cmd(inst, HFI_CMD_SYS_SESSION_END, true);
}
static int venus_session_abort(struct venus_inst *inst)
@@ -1176,7 +1265,7 @@ static int venus_session_abort(struct venus_inst *inst)
venus_flush_debug_queue(hdev);
- return venus_session_cmd(inst, HFI_CMD_SYS_SESSION_ABORT);
+ return venus_session_cmd(inst, HFI_CMD_SYS_SESSION_ABORT, true);
}
static int venus_session_flush(struct venus_inst *inst, u32 flush_mode)
@@ -1189,22 +1278,22 @@ static int venus_session_flush(struct venus_inst *inst, u32 flush_mode)
if (ret)
return ret;
- return venus_iface_cmdq_write(hdev, &pkt);
+ return venus_iface_cmdq_write(hdev, &pkt, true);
}
static int venus_session_start(struct venus_inst *inst)
{
- return venus_session_cmd(inst, HFI_CMD_SESSION_START);
+ return venus_session_cmd(inst, HFI_CMD_SESSION_START, true);
}
static int venus_session_stop(struct venus_inst *inst)
{
- return venus_session_cmd(inst, HFI_CMD_SESSION_STOP);
+ return venus_session_cmd(inst, HFI_CMD_SESSION_STOP, true);
}
static int venus_session_continue(struct venus_inst *inst)
{
- return venus_session_cmd(inst, HFI_CMD_SESSION_CONTINUE);
+ return venus_session_cmd(inst, HFI_CMD_SESSION_CONTINUE, false);
}
static int venus_session_etb(struct venus_inst *inst,
@@ -1221,7 +1310,7 @@ static int venus_session_etb(struct venus_inst *inst,
if (ret)
return ret;
- ret = venus_iface_cmdq_write(hdev, &pkt);
+ ret = venus_iface_cmdq_write(hdev, &pkt, false);
} else if (session_type == VIDC_SESSION_TYPE_ENC) {
struct hfi_session_empty_buffer_uncompressed_plane0_pkt pkt;
@@ -1229,7 +1318,7 @@ static int venus_session_etb(struct venus_inst *inst,
if (ret)
return ret;
- ret = venus_iface_cmdq_write(hdev, &pkt);
+ ret = venus_iface_cmdq_write(hdev, &pkt, false);
} else {
ret = -EINVAL;
}
@@ -1248,7 +1337,7 @@ static int venus_session_ftb(struct venus_inst *inst,
if (ret)
return ret;
- return venus_iface_cmdq_write(hdev, &pkt);
+ return venus_iface_cmdq_write(hdev, &pkt, false);
}
static int venus_session_set_buffers(struct venus_inst *inst,
@@ -1268,7 +1357,7 @@ static int venus_session_set_buffers(struct venus_inst *inst,
if (ret)
return ret;
- return venus_iface_cmdq_write(hdev, pkt);
+ return venus_iface_cmdq_write(hdev, pkt, false);
}
static int venus_session_unset_buffers(struct venus_inst *inst,
@@ -1288,17 +1377,17 @@ static int venus_session_unset_buffers(struct venus_inst *inst,
if (ret)
return ret;
- return venus_iface_cmdq_write(hdev, pkt);
+ return venus_iface_cmdq_write(hdev, pkt, true);
}
static int venus_session_load_res(struct venus_inst *inst)
{
- return venus_session_cmd(inst, HFI_CMD_SESSION_LOAD_RESOURCES);
+ return venus_session_cmd(inst, HFI_CMD_SESSION_LOAD_RESOURCES, true);
}
static int venus_session_release_res(struct venus_inst *inst)
{
- return venus_session_cmd(inst, HFI_CMD_SESSION_RELEASE_RESOURCES);
+ return venus_session_cmd(inst, HFI_CMD_SESSION_RELEASE_RESOURCES, true);
}
static int venus_session_parse_seq_hdr(struct venus_inst *inst, u32 seq_hdr,
@@ -1315,7 +1404,7 @@ static int venus_session_parse_seq_hdr(struct venus_inst *inst, u32 seq_hdr,
if (ret)
return ret;
- ret = venus_iface_cmdq_write(hdev, pkt);
+ ret = venus_iface_cmdq_write(hdev, pkt, false);
if (ret)
return ret;
@@ -1336,7 +1425,7 @@ static int venus_session_get_seq_hdr(struct venus_inst *inst, u32 seq_hdr,
if (ret)
return ret;
- return venus_iface_cmdq_write(hdev, pkt);
+ return venus_iface_cmdq_write(hdev, pkt, false);
}
static int venus_session_set_property(struct venus_inst *inst, u32 ptype,
@@ -1355,7 +1444,7 @@ static int venus_session_set_property(struct venus_inst *inst, u32 ptype,
if (ret)
return ret;
- return venus_iface_cmdq_write(hdev, pkt);
+ return venus_iface_cmdq_write(hdev, pkt, false);
}
static int venus_session_get_property(struct venus_inst *inst, u32 ptype)
@@ -1368,7 +1457,7 @@ static int venus_session_get_property(struct venus_inst *inst, u32 ptype)
if (ret)
return ret;
- return venus_iface_cmdq_write(hdev, &pkt);
+ return venus_iface_cmdq_write(hdev, &pkt, true);
}
static int venus_resume(struct venus_core *core)
@@ -1396,6 +1485,7 @@ static int venus_suspend_1xx(struct venus_core *core)
{
struct venus_hfi_device *hdev = to_hfi_priv(core);
struct device *dev = core->dev;
+ void __iomem *cpu_cs_base = hdev->core->cpu_cs_base;
u32 ctrl_status;
int ret;
@@ -1430,7 +1520,7 @@ static int venus_suspend_1xx(struct venus_core *core)
return -EINVAL;
}
- ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0);
+ ctrl_status = readl(cpu_cs_base + CPU_CS_SCIACMDARG0);
if (!(ctrl_status & CPU_CS_SCIACMDARG0_PC_READY)) {
mutex_unlock(&hdev->lock);
return -EINVAL;
@@ -1451,10 +1541,16 @@ static int venus_suspend_1xx(struct venus_core *core)
static bool venus_cpu_and_video_core_idle(struct venus_hfi_device *hdev)
{
+ void __iomem *wrapper_base = hdev->core->wrapper_base;
+ void __iomem *wrapper_tz_base = hdev->core->wrapper_tz_base;
+ void __iomem *cpu_cs_base = hdev->core->cpu_cs_base;
u32 ctrl_status, cpu_status;
- cpu_status = venus_readl(hdev, WRAPPER_CPU_STATUS);
- ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0);
+ if (IS_IRIS2(hdev->core) || IS_IRIS2_1(hdev->core) || IS_AR50_LITE(hdev->core))
+ cpu_status = readl(wrapper_tz_base + WRAPPER_TZ_CPU_STATUS_V6);
+ else
+ cpu_status = readl(wrapper_base + WRAPPER_CPU_STATUS);
+ ctrl_status = readl(cpu_cs_base + CPU_CS_SCIACMDARG0);
if (cpu_status & WRAPPER_CPU_STATUS_WFI &&
ctrl_status & CPU_CS_SCIACMDARG0_INIT_IDLE_MSG_MASK)
@@ -1465,10 +1561,16 @@ static bool venus_cpu_and_video_core_idle(struct venus_hfi_device *hdev)
static bool venus_cpu_idle_and_pc_ready(struct venus_hfi_device *hdev)
{
+ void __iomem *wrapper_base = hdev->core->wrapper_base;
+ void __iomem *wrapper_tz_base = hdev->core->wrapper_tz_base;
+ void __iomem *cpu_cs_base = hdev->core->cpu_cs_base;
u32 ctrl_status, cpu_status;
- cpu_status = venus_readl(hdev, WRAPPER_CPU_STATUS);
- ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0);
+ if (IS_IRIS2(hdev->core) || IS_IRIS2_1(hdev->core) || IS_AR50_LITE(hdev->core))
+ cpu_status = readl(wrapper_tz_base + WRAPPER_TZ_CPU_STATUS_V6);
+ else
+ cpu_status = readl(wrapper_base + WRAPPER_CPU_STATUS);
+ ctrl_status = readl(cpu_cs_base + CPU_CS_SCIACMDARG0);
if (cpu_status & WRAPPER_CPU_STATUS_WFI &&
ctrl_status & CPU_CS_SCIACMDARG0_PC_READY)
@@ -1481,6 +1583,8 @@ static int venus_suspend_3xx(struct venus_core *core)
{
struct venus_hfi_device *hdev = to_hfi_priv(core);
struct device *dev = core->dev;
+ void __iomem *cpu_cs_base = hdev->core->cpu_cs_base;
+ u32 ctrl_status;
bool val;
int ret;
@@ -1496,6 +1600,10 @@ static int venus_suspend_3xx(struct venus_core *core)
return -EINVAL;
}
+ ctrl_status = readl(cpu_cs_base + CPU_CS_SCIACMDARG0);
+ if (ctrl_status & CPU_CS_SCIACMDARG0_PC_READY)
+ goto power_off;
+
/*
* Power collapse sequence for Venus 3xx and 4xx versions:
* 1. Check for ARM9 and video core to be idle by checking WFI bit
@@ -1506,8 +1614,10 @@ static int venus_suspend_3xx(struct venus_core *core)
*/
ret = readx_poll_timeout(venus_cpu_and_video_core_idle, hdev, val, val,
1500, 100 * 1500);
- if (ret)
+ if (ret) {
+ dev_err(dev, "wait for cpu and video core idle fail (%d)\n", ret);
return ret;
+ }
ret = venus_prepare_power_collapse(hdev, false);
if (ret) {
@@ -1520,6 +1630,7 @@ static int venus_suspend_3xx(struct venus_core *core)
if (ret)
return ret;
+power_off:
mutex_lock(&hdev->lock);
ret = venus_power_off(hdev);
@@ -1538,7 +1649,7 @@ static int venus_suspend_3xx(struct venus_core *core)
static int venus_suspend(struct venus_core *core)
{
- if (IS_V3(core) || IS_V4(core))
+ if (IS_V3(core) || IS_V4(core) || IS_V6(core))
return venus_suspend_3xx(core);
return venus_suspend_1xx(core);
@@ -1547,7 +1658,6 @@ static int venus_suspend(struct venus_core *core)
static const struct hfi_ops venus_hfi_ops = {
.core_init = venus_core_init,
.core_deinit = venus_core_deinit,
- .core_ping = venus_core_ping,
.core_trigger_ssr = venus_core_trigger_ssr,
.session_init = venus_session_init,
@@ -1579,10 +1689,11 @@ void venus_hfi_destroy(struct venus_core *core)
{
struct venus_hfi_device *hdev = to_hfi_priv(core);
+ core->priv = NULL;
venus_interface_queues_release(hdev);
mutex_destroy(&hdev->lock);
kfree(hdev);
- core->priv = NULL;
+ disable_irq(core->irq);
core->ops = NULL;
}
@@ -1601,9 +1712,6 @@ int venus_hfi_create(struct venus_core *core)
hdev->suspended = true;
core->priv = hdev;
core->ops = &venus_hfi_ops;
- core->core_caps = ENC_ROTATION_CAPABILITY | ENC_SCALING_CAPABILITY |
- ENC_DEINTERLACE_CAPABILITY |
- DEC_MULTI_STREAM_CAPABILITY;
ret = venus_interface_queues_init(hdev);
if (ret)
@@ -1617,3 +1725,54 @@ err_kfree:
core->ops = NULL;
return ret;
}
+
+void venus_hfi_queues_reinit(struct venus_core *core)
+{
+ struct venus_hfi_device *hdev = to_hfi_priv(core);
+ struct hfi_queue_table_header *tbl_hdr;
+ struct iface_queue *queue;
+ struct hfi_sfr *sfr;
+ unsigned int i;
+
+ mutex_lock(&hdev->lock);
+
+ for (i = 0; i < IFACEQ_NUM; i++) {
+ queue = &hdev->queues[i];
+ queue->qhdr =
+ IFACEQ_GET_QHDR_START_ADDR(hdev->ifaceq_table.kva, i);
+
+ venus_set_qhdr_defaults(queue->qhdr);
+
+ queue->qhdr->start_addr = queue->qmem.da;
+
+ if (i == IFACEQ_CMD_IDX)
+ queue->qhdr->type |= HFI_HOST_TO_CTRL_CMD_Q;
+ else if (i == IFACEQ_MSG_IDX)
+ queue->qhdr->type |= HFI_CTRL_TO_HOST_MSG_Q;
+ else if (i == IFACEQ_DBG_IDX)
+ queue->qhdr->type |= HFI_CTRL_TO_HOST_DBG_Q;
+ }
+
+ tbl_hdr = hdev->ifaceq_table.kva;
+ tbl_hdr->version = 0;
+ tbl_hdr->size = IFACEQ_TABLE_SIZE;
+ tbl_hdr->qhdr0_offset = sizeof(struct hfi_queue_table_header);
+ tbl_hdr->qhdr_size = sizeof(struct hfi_queue_header);
+ tbl_hdr->num_q = IFACEQ_NUM;
+ tbl_hdr->num_active_q = IFACEQ_NUM;
+
+ /*
+ * Set receive request to zero on debug queue as there is no
+ * need of interrupt from video hardware for debug messages
+ */
+ queue = &hdev->queues[IFACEQ_DBG_IDX];
+ queue->qhdr->rx_req = 0;
+
+ sfr = hdev->sfr.kva;
+ sfr->buf_size = ALIGNED_SFR_SIZE;
+
+ /* ensure table and queue header structs are settled in memory */
+ wmb();
+
+ mutex_unlock(&hdev->lock);
+}