aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/qcom
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/qcom')
-rw-r--r--drivers/media/platform/qcom/camss/camss-csid.c9
-rw-r--r--drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c7
-rw-r--r--drivers/media/platform/qcom/camss/camss-csiphy.c25
-rw-r--r--drivers/media/platform/qcom/camss/camss-csiphy.h1
-rw-r--r--drivers/media/platform/qcom/camss/camss-ispif.c100
-rw-r--r--drivers/media/platform/qcom/camss/camss-ispif.h2
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe-4-7.c131
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe.c19
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe.h1
-rw-r--r--drivers/media/platform/qcom/camss/camss-video.c90
-rw-r--r--drivers/media/platform/qcom/camss/camss.c206
-rw-r--r--drivers/media/platform/qcom/camss/camss.h1
-rw-r--r--drivers/media/platform/qcom/venus/core.c41
-rw-r--r--drivers/media/platform/qcom/venus/core.h16
-rw-r--r--drivers/media/platform/qcom/venus/firmware.c17
-rw-r--r--drivers/media/platform/qcom/venus/hfi.c12
-rw-r--r--drivers/media/platform/qcom/venus/pm_helpers.c19
-rw-r--r--drivers/media/platform/qcom/venus/vdec.c32
-rw-r--r--drivers/media/platform/qcom/venus/venc.c33
-rw-r--r--drivers/media/platform/qcom/venus/venc_ctrls.c14
20 files changed, 634 insertions, 142 deletions
diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c
index 2ffcda06706b..be3fe76f3dc3 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.c
+++ b/drivers/media/platform/qcom/camss/camss-csid.c
@@ -383,7 +383,8 @@ static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
return 0;
return sink_code;
- } else if (csid->camss->version == CAMSS_8x96) {
+ } else if (csid->camss->version == CAMSS_8x96 ||
+ csid->camss->version == CAMSS_660) {
switch (sink_code) {
case MEDIA_BUS_FMT_SBGGR10_1X10:
{
@@ -718,7 +719,8 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable)
val |= df << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;
val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;
- if (csid->camss->version == CAMSS_8x96) {
+ if (csid->camss->version == CAMSS_8x96 ||
+ csid->camss->version == CAMSS_660) {
u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code;
u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code;
@@ -1098,7 +1100,8 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
csid->formats = csid_formats_8x16;
csid->nformats =
ARRAY_SIZE(csid_formats_8x16);
- } else if (camss->version == CAMSS_8x96) {
+ } else if (camss->version == CAMSS_8x96 ||
+ camss->version == CAMSS_660) {
csid->formats = csid_formats_8x96;
csid->nformats =
ARRAY_SIZE(csid_formats_8x96);
diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c
index 2e65caf1ecae..97cb9de85031 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c
+++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c
@@ -8,6 +8,7 @@
* Copyright (C) 2016-2018 Linaro Ltd.
*/
+#include "camss.h"
#include "camss-csiphy.h"
#include <linux/delay.h>
@@ -21,6 +22,7 @@
#define CSIPHY_3PH_LNn_CFG3(n) (0x008 + 0x100 * (n))
#define CSIPHY_3PH_LNn_CFG4(n) (0x00c + 0x100 * (n))
#define CSIPHY_3PH_LNn_CFG4_T_HS_CLK_MISS 0xa4
+#define CSIPHY_3PH_LNn_CFG4_T_HS_CLK_MISS_660 0xa5
#define CSIPHY_3PH_LNn_CFG5(n) (0x010 + 0x100 * (n))
#define CSIPHY_3PH_LNn_CFG5_T_HS_DTERM 0x02
#define CSIPHY_3PH_LNn_CFG5_HS_REC_EQ_FQ_INT 0x50
@@ -198,7 +200,10 @@ static void csiphy_lanes_enable(struct csiphy_device *csiphy,
val = CSIPHY_3PH_LNn_CFG1_SWI_REC_DLY_PRG;
writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_CFG1(l));
- val = CSIPHY_3PH_LNn_CFG4_T_HS_CLK_MISS;
+ if (csiphy->camss->version == CAMSS_660)
+ val = CSIPHY_3PH_LNn_CFG4_T_HS_CLK_MISS_660;
+ else
+ val = CSIPHY_3PH_LNn_CFG4_T_HS_CLK_MISS;
writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_CFG4(l));
val = CSIPHY_3PH_LNn_MISC1_IS_CLKLANE;
diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c
index 85b24054f35e..509c9a59c09c 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy.c
+++ b/drivers/media/platform/qcom/camss/camss-csiphy.c
@@ -113,9 +113,7 @@ static int csiphy_set_clock_rates(struct csiphy_device *csiphy)
for (i = 0; i < csiphy->nclocks; i++) {
struct camss_clock *clock = &csiphy->clock[i];
- if (!strcmp(clock->name, "csiphy0_timer") ||
- !strcmp(clock->name, "csiphy1_timer") ||
- !strcmp(clock->name, "csiphy2_timer")) {
+ if (csiphy->rate_set[i]) {
u8 bpp = csiphy_get_bpp(csiphy->formats,
csiphy->nformats,
csiphy->fmt[MSM_CSIPHY_PAD_SINK].code);
@@ -554,7 +552,8 @@ int msm_csiphy_subdev_init(struct camss *camss,
csiphy->ops = &csiphy_ops_2ph_1_0;
csiphy->formats = csiphy_formats_8x16;
csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x16);
- } else if (camss->version == CAMSS_8x96) {
+ } else if (camss->version == CAMSS_8x96 ||
+ camss->version == CAMSS_660) {
csiphy->ops = &csiphy_ops_3ph_1_0;
csiphy->formats = csiphy_formats_8x96;
csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x96);
@@ -612,6 +611,13 @@ int msm_csiphy_subdev_init(struct camss *camss,
if (!csiphy->clock)
return -ENOMEM;
+ csiphy->rate_set = devm_kcalloc(dev,
+ csiphy->nclocks,
+ sizeof(*csiphy->rate_set),
+ GFP_KERNEL);
+ if (!csiphy->rate_set)
+ return -ENOMEM;
+
for (i = 0; i < csiphy->nclocks; i++) {
struct camss_clock *clock = &csiphy->clock[i];
@@ -639,6 +645,17 @@ int msm_csiphy_subdev_init(struct camss *camss,
for (j = 0; j < clock->nfreqs; j++)
clock->freq[j] = res->clock_rate[i][j];
+
+ if (!strcmp(clock->name, "csiphy0_timer") ||
+ !strcmp(clock->name, "csiphy1_timer") ||
+ !strcmp(clock->name, "csiphy2_timer"))
+ csiphy->rate_set[i] = true;
+
+ if (camss->version == CAMSS_660 &&
+ (!strcmp(clock->name, "csi0_phy") ||
+ !strcmp(clock->name, "csi1_phy") ||
+ !strcmp(clock->name, "csi2_phy")))
+ csiphy->rate_set[i] = true;
}
return 0;
diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.h b/drivers/media/platform/qcom/camss/camss-csiphy.h
index 376f865ad383..f7967ef836dc 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy.h
+++ b/drivers/media/platform/qcom/camss/camss-csiphy.h
@@ -66,6 +66,7 @@ struct csiphy_device {
u32 irq;
char irq_name[30];
struct camss_clock *clock;
+ bool *rate_set;
int nclocks;
u32 timer_clk_rate;
struct csiphy_config cfg;
diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c
index db94cfd6c508..adeb92808998 100644
--- a/drivers/media/platform/qcom/camss/camss-ispif.c
+++ b/drivers/media/platform/qcom/camss/camss-ispif.c
@@ -26,6 +26,7 @@
#define MSM_ISPIF_NAME "msm_ispif"
#define ISPIF_RST_CMD_0 0x008
+#define ISPIF_RST_CMD_1 0x00c
#define ISPIF_RST_CMD_0_STROBED_RST_EN (1 << 0)
#define ISPIF_RST_CMD_0_MISC_LOGIC_RST (1 << 1)
#define ISPIF_RST_CMD_0_SW_REG_RST (1 << 2)
@@ -179,7 +180,10 @@ static irqreturn_t ispif_isr_8x96(int irq, void *dev)
writel(0x1, ispif->base + ISPIF_IRQ_GLOBAL_CLEAR_CMD);
if ((value0 >> 27) & 0x1)
- complete(&ispif->reset_complete);
+ complete(&ispif->reset_complete[0]);
+
+ if ((value3 >> 27) & 0x1)
+ complete(&ispif->reset_complete[1]);
if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW))
dev_err_ratelimited(to_device(ispif), "VFE0 pix0 overflow\n");
@@ -237,7 +241,7 @@ static irqreturn_t ispif_isr_8x16(int irq, void *dev)
writel(0x1, ispif->base + ISPIF_IRQ_GLOBAL_CLEAR_CMD);
if ((value0 >> 27) & 0x1)
- complete(&ispif->reset_complete);
+ complete(&ispif->reset_complete[0]);
if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW))
dev_err_ratelimited(to_device(ispif), "VFE0 pix0 overflow\n");
@@ -257,33 +261,18 @@ static irqreturn_t ispif_isr_8x16(int irq, void *dev)
return IRQ_HANDLED;
}
-/*
- * ispif_reset - Trigger reset on ISPIF module and wait to complete
- * @ispif: ISPIF device
- *
- * Return 0 on success or a negative error code otherwise
- */
-static int ispif_reset(struct ispif_device *ispif)
+static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id)
{
unsigned long time;
u32 val;
- int ret;
-
- ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE0);
- if (ret < 0)
- return ret;
- ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE1);
- if (ret < 0)
- return ret;
-
- ret = camss_enable_clocks(ispif->nclocks_for_reset,
- ispif->clock_for_reset,
- to_device(ispif));
- if (ret < 0)
- return ret;
+ if (vfe_id > (to_camss(ispif)->vfe_num - 1)) {
+ dev_err(to_device(ispif),
+ "Error: asked reset for invalid VFE%d\n", vfe_id);
+ return -ENOENT;
+ }
- reinit_completion(&ispif->reset_complete);
+ reinit_completion(&ispif->reset_complete[vfe_id]);
val = ISPIF_RST_CMD_0_STROBED_RST_EN |
ISPIF_RST_CMD_0_MISC_LOGIC_RST |
@@ -303,15 +292,50 @@ static int ispif_reset(struct ispif_device *ispif)
ISPIF_RST_CMD_0_RDI_OUTPUT_1_MISR_RST |
ISPIF_RST_CMD_0_RDI_OUTPUT_2_MISR_RST;
- writel_relaxed(val, ispif->base + ISPIF_RST_CMD_0);
+ if (vfe_id == 1)
+ writel_relaxed(val, ispif->base + ISPIF_RST_CMD_1);
+ else
+ writel_relaxed(val, ispif->base + ISPIF_RST_CMD_0);
- time = wait_for_completion_timeout(&ispif->reset_complete,
+ time = wait_for_completion_timeout(&ispif->reset_complete[vfe_id],
msecs_to_jiffies(ISPIF_RESET_TIMEOUT_MS));
if (!time) {
- dev_err(to_device(ispif), "ISPIF reset timeout\n");
- ret = -EIO;
+ dev_err(to_device(ispif),
+ "ISPIF for VFE%d reset timeout\n", vfe_id);
+ return -EIO;
}
+ return 0;
+}
+
+/*
+ * ispif_reset - Trigger reset on ISPIF module and wait to complete
+ * @ispif: ISPIF device
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int ispif_reset(struct ispif_device *ispif, u8 vfe_id)
+{
+ int ret;
+
+ ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE0);
+ if (ret < 0)
+ return ret;
+
+ ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE1);
+ if (ret < 0)
+ return ret;
+
+ ret = camss_enable_clocks(ispif->nclocks_for_reset,
+ ispif->clock_for_reset,
+ to_device(ispif));
+ if (ret < 0)
+ return ret;
+
+ ret = ispif_vfe_reset(ispif, vfe_id);
+ if (ret)
+ dev_dbg(to_device(ispif), "ISPIF Reset failed\n");
+
camss_disable_clocks(ispif->nclocks_for_reset, ispif->clock_for_reset);
camss_pm_domain_off(to_camss(ispif), PM_DOMAIN_VFE0);
@@ -355,7 +379,7 @@ static int ispif_set_power(struct v4l2_subdev *sd, int on)
goto exit;
}
- ret = ispif_reset(ispif);
+ ret = ispif_reset(ispif, line->vfe_id);
if (ret < 0) {
pm_runtime_put_sync(dev);
camss_disable_clocks(ispif->nclocks, ispif->clock);
@@ -801,7 +825,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
ispif_select_csid(ispif, intf, csid, vfe, 1);
ispif_select_cid(ispif, intf, cid, vfe, 1);
ispif_config_irq(ispif, intf, vfe, 1);
- if (to_camss(ispif)->version == CAMSS_8x96)
+ if (to_camss(ispif)->version == CAMSS_8x96 ||
+ to_camss(ispif)->version == CAMSS_660)
ispif_config_pack(ispif,
line->fmt[MSM_ISPIF_PAD_SINK].code,
intf, cid, vfe, 1);
@@ -818,7 +843,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
return ret;
mutex_lock(&ispif->config_lock);
- if (to_camss(ispif)->version == CAMSS_8x96)
+ if (to_camss(ispif)->version == CAMSS_8x96 ||
+ to_camss(ispif)->version == CAMSS_660)
ispif_config_pack(ispif,
line->fmt[MSM_ISPIF_PAD_SINK].code,
intf, cid, vfe, 0);
@@ -1074,7 +1100,8 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
/* Number of ISPIF lines - same as number of CSID hardware modules */
if (to_camss(ispif)->version == CAMSS_8x16)
ispif->line_num = 2;
- else if (to_camss(ispif)->version == CAMSS_8x96)
+ else if (to_camss(ispif)->version == CAMSS_8x96 ||
+ to_camss(ispif)->version == CAMSS_660)
ispif->line_num = 4;
else
return -EINVAL;
@@ -1092,7 +1119,8 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
ispif->line[i].formats = ispif_formats_8x16;
ispif->line[i].nformats =
ARRAY_SIZE(ispif_formats_8x16);
- } else if (to_camss(ispif)->version == CAMSS_8x96) {
+ } else if (to_camss(ispif)->version == CAMSS_8x96 ||
+ to_camss(ispif)->version == CAMSS_660) {
ispif->line[i].formats = ispif_formats_8x96;
ispif->line[i].nformats =
ARRAY_SIZE(ispif_formats_8x96);
@@ -1132,7 +1160,8 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
if (to_camss(ispif)->version == CAMSS_8x16)
ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x16,
IRQF_TRIGGER_RISING, ispif->irq_name, ispif);
- else if (to_camss(ispif)->version == CAMSS_8x96)
+ else if (to_camss(ispif)->version == CAMSS_8x96 ||
+ to_camss(ispif)->version == CAMSS_660)
ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x96,
IRQF_TRIGGER_RISING, ispif->irq_name, ispif);
else
@@ -1192,7 +1221,8 @@ int msm_ispif_subdev_init(struct ispif_device *ispif,
mutex_init(&ispif->config_lock);
- init_completion(&ispif->reset_complete);
+ for (i = 0; i < MSM_ISPIF_VFE_NUM; i++)
+ init_completion(&ispif->reset_complete[i]);
return 0;
}
diff --git a/drivers/media/platform/qcom/camss/camss-ispif.h b/drivers/media/platform/qcom/camss/camss-ispif.h
index 1a5ba2425a42..4132174f7ea1 100644
--- a/drivers/media/platform/qcom/camss/camss-ispif.h
+++ b/drivers/media/platform/qcom/camss/camss-ispif.h
@@ -56,7 +56,7 @@ struct ispif_device {
int nclocks;
struct camss_clock *clock_for_reset;
int nclocks_for_reset;
- struct completion reset_complete;
+ struct completion reset_complete[MSM_ISPIF_VFE_NUM];
int power_count;
struct mutex power_lock;
struct ispif_intf_cmd_reg intf_cmd[MSM_ISPIF_VFE_NUM];
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
index 0dca8bf9281e..b5704a2f119b 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
@@ -133,6 +133,11 @@
#define VFE_0_BUS_BDG_QOS_CFG_7 0x420
#define VFE_0_BUS_BDG_QOS_CFG_7_CFG 0x0001aaa9
+#define VFE48_0_BUS_BDG_QOS_CFG_0_CFG 0xaaa5aaa5
+#define VFE48_0_BUS_BDG_QOS_CFG_3_CFG 0xaa55aaa5
+#define VFE48_0_BUS_BDG_QOS_CFG_4_CFG 0xaa55aa55
+#define VFE48_0_BUS_BDG_QOS_CFG_7_CFG 0x0005aa55
+
#define VFE_0_BUS_BDG_DS_CFG_0 0x424
#define VFE_0_BUS_BDG_DS_CFG_0_CFG 0xcccc0011
#define VFE_0_BUS_BDG_DS_CFG_1 0x428
@@ -153,6 +158,9 @@
#define VFE_0_BUS_BDG_DS_CFG_16 0x464
#define VFE_0_BUS_BDG_DS_CFG_16_CFG 0x40000103
+#define VFE48_0_BUS_BDG_DS_CFG_0_CFG 0xcccc1111
+#define VFE48_0_BUS_BDG_DS_CFG_16_CFG 0x00000110
+
#define VFE_0_RDI_CFG_x(x) (0x46c + (0x4 * (x)))
#define VFE_0_RDI_CFG_x_RDI_STREAM_SEL_SHIFT 28
#define VFE_0_RDI_CFG_x_RDI_STREAM_SEL_MASK (0xf << 28)
@@ -231,6 +239,9 @@
#define VFE_0_REALIGN_BUF_CFG_CR_ODD_PIXEL BIT(3)
#define VFE_0_REALIGN_BUF_CFG_HSUB_ENABLE BIT(4)
+#define VFE48_0_BUS_IMAGE_MASTER_CMD 0xcec
+#define VFE48_0_BUS_IMAGE_MASTER_n_SHIFT(x) (2 * (x))
+
#define CAMIF_TIMEOUT_SLEEP_US 1000
#define CAMIF_TIMEOUT_ALL_US 1000000
@@ -246,7 +257,7 @@ static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev)
dev_err(dev, "VFE HW Version = 0x%08x\n", hw_version);
}
-static u16 vfe_get_ub_size(u8 vfe_id)
+static u16 vfe47_get_ub_size(u8 vfe_id)
{
if (vfe_id == 0)
return MSM_VFE_VFE0_UB_SIZE_RDI;
@@ -299,7 +310,7 @@ static void vfe_halt_clear(struct vfe_device *vfe)
writel_relaxed(0x0, vfe->base + VFE_0_BUS_BDG_CMD);
}
-static void vfe_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable)
+static void vfe47_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable)
{
if (enable)
vfe_reg_set(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_CFG(wm),
@@ -883,7 +894,7 @@ static void vfe_set_clamp_cfg(struct vfe_device *vfe)
writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MIN_CFG);
}
-static void vfe_set_qos(struct vfe_device *vfe)
+static void vfe47_set_qos(struct vfe_device *vfe)
{
u32 val = VFE_0_BUS_BDG_QOS_CFG_0_CFG;
u32 val7 = VFE_0_BUS_BDG_QOS_CFG_7_CFG;
@@ -898,7 +909,7 @@ static void vfe_set_qos(struct vfe_device *vfe)
writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7);
}
-static void vfe_set_ds(struct vfe_device *vfe)
+static void vfe47_set_ds(struct vfe_device *vfe)
{
u32 val = VFE_0_BUS_BDG_DS_CFG_0_CFG;
u32 val16 = VFE_0_BUS_BDG_DS_CFG_16_CFG;
@@ -1098,11 +1109,115 @@ static irqreturn_t vfe_isr(int irq, void *dev)
const struct vfe_hw_ops vfe_ops_4_7 = {
.hw_version_read = vfe_hw_version_read,
- .get_ub_size = vfe_get_ub_size,
+ .get_ub_size = vfe47_get_ub_size,
+ .global_reset = vfe_global_reset,
+ .halt_request = vfe_halt_request,
+ .halt_clear = vfe_halt_clear,
+ .wm_enable = vfe47_wm_enable,
+ .wm_frame_based = vfe_wm_frame_based,
+ .wm_line_based = vfe_wm_line_based,
+ .wm_set_framedrop_period = vfe_wm_set_framedrop_period,
+ .wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern,
+ .wm_set_ub_cfg = vfe_wm_set_ub_cfg,
+ .bus_reload_wm = vfe_bus_reload_wm,
+ .wm_set_ping_addr = vfe_wm_set_ping_addr,
+ .wm_set_pong_addr = vfe_wm_set_pong_addr,
+ .wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
+ .bus_enable_wr_if = vfe_bus_enable_wr_if,
+ .bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
+ .wm_set_subsample = vfe_wm_set_subsample,
+ .bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
+ .set_xbar_cfg = vfe_set_xbar_cfg,
+ .set_realign_cfg = vfe_set_realign_cfg,
+ .set_rdi_cid = vfe_set_rdi_cid,
+ .reg_update = vfe_reg_update,
+ .reg_update_clear = vfe_reg_update_clear,
+ .enable_irq_wm_line = vfe_enable_irq_wm_line,
+ .enable_irq_pix_line = vfe_enable_irq_pix_line,
+ .enable_irq_common = vfe_enable_irq_common,
+ .set_demux_cfg = vfe_set_demux_cfg,
+ .set_scale_cfg = vfe_set_scale_cfg,
+ .set_crop_cfg = vfe_set_crop_cfg,
+ .set_clamp_cfg = vfe_set_clamp_cfg,
+ .set_qos = vfe47_set_qos,
+ .set_ds = vfe47_set_ds,
+ .set_cgc_override = vfe_set_cgc_override,
+ .set_camif_cfg = vfe_set_camif_cfg,
+ .set_camif_cmd = vfe_set_camif_cmd,
+ .set_module_cfg = vfe_set_module_cfg,
+ .camif_wait_for_stop = vfe_camif_wait_for_stop,
+ .isr_read = vfe_isr_read,
+ .violation_read = vfe_violation_read,
+ .isr = vfe_isr,
+};
+
+static u16 vfe48_get_ub_size(u8 vfe_id)
+{
+ /* On VFE4.8 the ub-size is the same on both instances */
+ return MSM_VFE_VFE0_UB_SIZE_RDI;
+}
+
+static void vfe48_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable)
+{
+ if (enable)
+ writel_relaxed(2 << VFE48_0_BUS_IMAGE_MASTER_n_SHIFT(wm),
+ vfe->base + VFE48_0_BUS_IMAGE_MASTER_CMD);
+ else
+ writel_relaxed(1 << VFE48_0_BUS_IMAGE_MASTER_n_SHIFT(wm),
+ vfe->base + VFE48_0_BUS_IMAGE_MASTER_CMD);
+
+ /* The WM must be enabled before sending other commands */
+ wmb();
+}
+
+static void vfe48_set_qos(struct vfe_device *vfe)
+{
+ u32 val = VFE48_0_BUS_BDG_QOS_CFG_0_CFG;
+ u32 val3 = VFE48_0_BUS_BDG_QOS_CFG_3_CFG;
+ u32 val4 = VFE48_0_BUS_BDG_QOS_CFG_4_CFG;
+ u32 val7 = VFE48_0_BUS_BDG_QOS_CFG_7_CFG;
+
+ writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_0);
+ writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_1);
+ writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_2);
+ writel_relaxed(val3, vfe->base + VFE_0_BUS_BDG_QOS_CFG_3);
+ writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_4);
+ writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_5);
+ writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_6);
+ writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7);
+}
+
+static void vfe48_set_ds(struct vfe_device *vfe)
+{
+ u32 val = VFE48_0_BUS_BDG_DS_CFG_0_CFG;
+ u32 val16 = VFE48_0_BUS_BDG_DS_CFG_16_CFG;
+
+ writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_0);
+ writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_1);
+ writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_2);
+ writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_3);
+ writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_4);
+ writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_5);
+ writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_6);
+ writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_7);
+ writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_8);
+ writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_9);
+ writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_10);
+ writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_11);
+ writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_12);
+ writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_13);
+ writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_14);
+ writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_15);
+ writel_relaxed(val16, vfe->base + VFE_0_BUS_BDG_DS_CFG_16);
+}
+
+const struct vfe_hw_ops vfe_ops_4_8 = {
+ .hw_version_read = vfe_hw_version_read,
+ .get_ub_size = vfe48_get_ub_size,
.global_reset = vfe_global_reset,
.halt_request = vfe_halt_request,
.halt_clear = vfe_halt_clear,
- .wm_enable = vfe_wm_enable,
+ .wm_enable = vfe48_wm_enable,
.wm_frame_based = vfe_wm_frame_based,
.wm_line_based = vfe_wm_line_based,
.wm_set_framedrop_period = vfe_wm_set_framedrop_period,
@@ -1128,8 +1243,8 @@ const struct vfe_hw_ops vfe_ops_4_7 = {
.set_scale_cfg = vfe_set_scale_cfg,
.set_crop_cfg = vfe_set_crop_cfg,
.set_clamp_cfg = vfe_set_clamp_cfg,
- .set_qos = vfe_set_qos,
- .set_ds = vfe_set_ds,
+ .set_qos = vfe48_set_qos,
+ .set_ds = vfe48_set_ds,
.set_cgc_override = vfe_set_cgc_override,
.set_camif_cfg = vfe_set_camif_cfg,
.set_camif_cmd = vfe_set_camif_cmd,
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index b7d2293a5004..fae2b513b2f9 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -205,7 +205,8 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
return sink_code;
}
- else if (vfe->camss->version == CAMSS_8x96)
+ else if (vfe->camss->version == CAMSS_8x96 ||
+ vfe->camss->version == CAMSS_660)
switch (sink_code) {
case MEDIA_BUS_FMT_YUYV8_2X8:
{
@@ -1991,12 +1992,19 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
vfe->isr_ops.comp_done = vfe_isr_comp_done;
vfe->isr_ops.wm_done = vfe_isr_wm_done;
- if (camss->version == CAMSS_8x16)
+ switch (camss->version) {
+ case CAMSS_8x16:
vfe->ops = &vfe_ops_4_1;
- else if (camss->version == CAMSS_8x96)
+ break;
+ case CAMSS_8x96:
vfe->ops = &vfe_ops_4_7;
- else
+ break;
+ case CAMSS_660:
+ vfe->ops = &vfe_ops_4_8;
+ break;
+ default:
return -EINVAL;
+ }
/* Memory */
@@ -2095,7 +2103,8 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
l->formats = formats_rdi_8x16;
l->nformats = ARRAY_SIZE(formats_rdi_8x16);
}
- } else if (camss->version == CAMSS_8x96) {
+ } else if (camss->version == CAMSS_8x96 ||
+ camss->version == CAMSS_660) {
if (i == VFE_LINE_PIX) {
l->formats = formats_pix_8x96;
l->nformats = ARRAY_SIZE(formats_pix_8x96);
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index a90b0d2cc6de..5bce6736e4bb 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -180,5 +180,6 @@ void msm_vfe_get_vfe_line_id(struct media_entity *entity, enum vfe_line_id *id);
extern const struct vfe_hw_ops vfe_ops_4_1;
extern const struct vfe_hw_ops vfe_ops_4_7;
+extern const struct vfe_hw_ops vfe_ops_4_8;
#endif /* QC_MSM_CAMSS_VFE_H */
diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c
index 114c3ae4a4ab..bd9334af1c73 100644
--- a/drivers/media/platform/qcom/camss/camss-video.c
+++ b/drivers/media/platform/qcom/camss/camss-video.c
@@ -535,20 +535,38 @@ static int video_querycap(struct file *file, void *fh,
return 0;
}
-/*
- * Returns the index in the video->formats[] array of the element which
- * has the "ndx"th unique value of pixelformat field.
- * If not found (no more unique pixelformat's) returns -EINVAL.
- */
-static int video_get_unique_pixelformat_by_index(struct camss_video *video,
- int ndx)
+static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
{
+ struct camss_video *video = video_drvdata(file);
int i, j, k;
+ u32 mcode = f->mbus_code;
- /* find index "i" of "k"th unique pixelformat in formats array */
+ if (f->type != video->type)
+ return -EINVAL;
+
+ if (f->index >= video->nformats)
+ return -EINVAL;
+
+ /*
+ * Find index "i" of "k"th unique pixelformat in formats array.
+ *
+ * If f->mbus_code passed to video_enum_fmt() is not zero, a device
+ * with V4L2_CAP_IO_MC capability restricts enumeration to only the
+ * pixel formats that can be produced from that media bus code.
+ * This is implemented by skipping video->formats[] entries with
+ * code != f->mbus_code (if f->mbus_code is not zero).
+ * If the f->mbus_code passed to video_enum_fmt() is not supported,
+ * -EINVAL is returned.
+ * If f->mbus_code is zero, all the pixel formats are enumerated.
+ */
k = -1;
for (i = 0; i < video->nformats; i++) {
+ if (mcode != 0 && video->formats[i].code != mcode)
+ continue;
+
for (j = 0; j < i; j++) {
+ if (mcode != 0 && video->formats[j].code != mcode)
+ continue;
if (video->formats[i].pixelformat ==
video->formats[j].pixelformat)
break;
@@ -557,53 +575,16 @@ static int video_get_unique_pixelformat_by_index(struct camss_video *video,
if (j == i)
k++;
- if (k == ndx)
- return i;
- }
-
- return -EINVAL;
-}
-
-/*
- * Returns the index in the video->formats[] array of the element which
- * has code equal to mcode.
- * If not found returns -EINVAL.
- */
-static int video_get_pixelformat_by_mbus_code(struct camss_video *video,
- u32 mcode)
-{
- int i;
-
- for (i = 0; i < video->nformats; i++) {
- if (video->formats[i].code == mcode)
- return i;
- }
-
- return -EINVAL;
-}
-
-static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
-{
- struct camss_video *video = video_drvdata(file);
- int i;
-
- if (f->type != video->type)
- return -EINVAL;
-
- if (f->index >= video->nformats)
- return -EINVAL;
-
- if (f->mbus_code) {
- /* Each entry in formats[] table has unique mbus_code */
- if (f->index > 0)
- return -EINVAL;
-
- i = video_get_pixelformat_by_mbus_code(video, f->mbus_code);
- } else {
- i = video_get_unique_pixelformat_by_index(video, f->index);
+ if (k == f->index)
+ break;
}
- if (i < 0)
+ if (k < f->index)
+ /*
+ * All the unique pixel formats matching the arguments
+ * have been enumerated (k >= 0 and f->index > 0), or
+ * no pixel formats match the non-zero f->mbus_code (k == -1).
+ */
return -EINVAL;
f->pixelformat = video->formats[i].pixelformat;
@@ -970,7 +951,8 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
video->formats = formats_rdi_8x16;
video->nformats = ARRAY_SIZE(formats_rdi_8x16);
}
- } else if (video->camss->version == CAMSS_8x96) {
+ } else if (video->camss->version == CAMSS_8x96 ||
+ video->camss->version == CAMSS_660) {
if (is_pix) {
video->formats = formats_pix_8x96;
video->nformats = ARRAY_SIZE(formats_pix_8x96);
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 9186881afc98..8fefce57bc49 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -283,6 +283,188 @@ static const struct resources vfe_res_8x96[] = {
}
};
+static const struct resources csiphy_res_660[] = {
+ /* CSIPHY0 */
+ {
+ .regulator = { NULL },
+ .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy0_timer",
+ "csi0_phy", "csiphy_ahb2crif" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 0 },
+ { 100000000, 200000000, 269333333 },
+ { 0 } },
+ .reg = { "csiphy0", "csiphy0_clk_mux" },
+ .interrupt = { "csiphy0" }
+ },
+
+ /* CSIPHY1 */
+ {
+ .regulator = { NULL },
+ .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy1_timer",
+ "csi1_phy", "csiphy_ahb2crif" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 0 },
+ { 100000000, 200000000, 269333333 },
+ { 0 } },
+ .reg = { "csiphy1", "csiphy1_clk_mux" },
+ .interrupt = { "csiphy1" }
+ },
+
+ /* CSIPHY2 */
+ {
+ .regulator = { NULL },
+ .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy2_timer",
+ "csi2_phy", "csiphy_ahb2crif" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 0 },
+ { 100000000, 200000000, 269333333 },
+ { 0 } },
+ .reg = { "csiphy2", "csiphy2_clk_mux" },
+ .interrupt = { "csiphy2" }
+ }
+};
+
+static const struct resources csid_res_660[] = {
+ /* CSID0 */
+ {
+ .regulator = { "vdda", "vdd_sec" },
+ .clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb",
+ "csi0", "csi0_phy", "csi0_pix", "csi0_rdi",
+ "cphy_csid0" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 100000000, 200000000, 310000000,
+ 404000000, 465000000 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "csid0" },
+ .interrupt = { "csid0" }
+ },
+
+ /* CSID1 */
+ {
+ .regulator = { "vdda", "vdd_sec" },
+ .clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb",
+ "csi1", "csi1_phy", "csi1_pix", "csi1_rdi",
+ "cphy_csid1" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 100000000, 200000000, 310000000,
+ 404000000, 465000000 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "csid1" },
+ .interrupt = { "csid1" }
+ },
+
+ /* CSID2 */
+ {
+ .regulator = { "vdda", "vdd_sec" },
+ .clock = { "top_ahb", "ispif_ahb", "csi2_ahb", "ahb",
+ "csi2", "csi2_phy", "csi2_pix", "csi2_rdi",
+ "cphy_csid2" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 100000000, 200000000, 310000000,
+ 404000000, 465000000 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "csid2" },
+ .interrupt = { "csid2" }
+ },
+
+ /* CSID3 */
+ {
+ .regulator = { "vdda", "vdd_sec" },
+ .clock = { "top_ahb", "ispif_ahb", "csi3_ahb", "ahb",
+ "csi3", "csi3_phy", "csi3_pix", "csi3_rdi",
+ "cphy_csid3" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 100000000, 200000000, 310000000,
+ 404000000, 465000000 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "csid3" },
+ .interrupt = { "csid3" }
+ }
+};
+
+static const struct resources_ispif ispif_res_660 = {
+ /* ISPIF */
+ .clock = { "top_ahb", "ahb", "ispif_ahb",
+ "csi0", "csi0_pix", "csi0_rdi",
+ "csi1", "csi1_pix", "csi1_rdi",
+ "csi2", "csi2_pix", "csi2_rdi",
+ "csi3", "csi3_pix", "csi3_rdi" },
+ .clock_for_reset = { "vfe0", "csi_vfe0", "vfe1", "csi_vfe1" },
+ .reg = { "ispif", "csi_clk_mux" },
+ .interrupt = "ispif"
+};
+
+static const struct resources vfe_res_660[] = {
+ /* VFE0 */
+ {
+ .regulator = { NULL },
+ .clock = { "throttle_axi", "top_ahb", "ahb", "vfe0",
+ "csi_vfe0", "vfe_ahb", "vfe0_ahb", "vfe_axi",
+ "vfe0_stream"},
+ .clock_rate = { { 0 },
+ { 0 },
+ { 0 },
+ { 120000000, 200000000, 256000000,
+ 300000000, 404000000, 480000000,
+ 540000000, 576000000 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "vfe0" },
+ .interrupt = { "vfe0" }
+ },
+
+ /* VFE1 */
+ {
+ .regulator = { NULL },
+ .clock = { "throttle_axi", "top_ahb", "ahb", "vfe1",
+ "csi_vfe1", "vfe_ahb", "vfe1_ahb", "vfe_axi",
+ "vfe1_stream"},
+ .clock_rate = { { 0 },
+ { 0 },
+ { 0 },
+ { 120000000, 200000000, 256000000,
+ 300000000, 404000000, 480000000,
+ 540000000, 576000000 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "vfe1" },
+ .interrupt = { "vfe1" }
+ }
+};
+
/*
* camss_add_clock_margin - Add margin to clock frequency rate
* @rate: Clock frequency rate
@@ -397,7 +579,8 @@ int camss_get_pixel_clock(struct media_entity *entity, u32 *pixel_clock)
int camss_pm_domain_on(struct camss *camss, int id)
{
- if (camss->version == CAMSS_8x96) {
+ if (camss->version == CAMSS_8x96 ||
+ camss->version == CAMSS_660) {
camss->genpd_link[id] = device_link_add(camss->dev,
camss->genpd[id], DL_FLAG_STATELESS |
DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
@@ -411,7 +594,8 @@ int camss_pm_domain_on(struct camss *camss, int id)
void camss_pm_domain_off(struct camss *camss, int id)
{
- if (camss->version == CAMSS_8x96)
+ if (camss->version == CAMSS_8x96 ||
+ camss->version == CAMSS_660)
device_link_del(camss->genpd_link[id]);
}
@@ -533,6 +717,11 @@ static int camss_init_subdevices(struct camss *camss)
csid_res = csid_res_8x96;
ispif_res = &ispif_res_8x96;
vfe_res = vfe_res_8x96;
+ } else if (camss->version == CAMSS_660) {
+ csiphy_res = csiphy_res_660;
+ csid_res = csid_res_660;
+ ispif_res = &ispif_res_660;
+ vfe_res = vfe_res_660;
} else {
return -EINVAL;
}
@@ -833,6 +1022,12 @@ static int camss_probe(struct platform_device *pdev)
camss->csiphy_num = 3;
camss->csid_num = 4;
camss->vfe_num = 2;
+ } else if (of_device_is_compatible(dev->of_node,
+ "qcom,sdm660-camss")) {
+ camss->version = CAMSS_660;
+ camss->csiphy_num = 3;
+ camss->csid_num = 4;
+ camss->vfe_num = 2;
} else {
ret = -EINVAL;
goto err_free;
@@ -919,7 +1114,8 @@ static int camss_probe(struct platform_device *pdev)
}
}
- if (camss->version == CAMSS_8x96) {
+ if (camss->version == CAMSS_8x96 ||
+ camss->version == CAMSS_660) {
camss->genpd[PM_DOMAIN_VFE0] = dev_pm_domain_attach_by_id(
camss->dev, PM_DOMAIN_VFE0);
if (IS_ERR(camss->genpd[PM_DOMAIN_VFE0]))
@@ -958,7 +1154,8 @@ void camss_delete(struct camss *camss)
pm_runtime_disable(camss->dev);
- if (camss->version == CAMSS_8x96) {
+ if (camss->version == CAMSS_8x96 ||
+ camss->version == CAMSS_660) {
dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE0], true);
dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE1], true);
}
@@ -989,6 +1186,7 @@ static int camss_remove(struct platform_device *pdev)
static const struct of_device_id camss_dt_match[] = {
{ .compatible = "qcom,msm8916-camss" },
{ .compatible = "qcom,msm8996-camss" },
+ { .compatible = "qcom,sdm660-camss" },
{ }
};
diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
index 1376b07889bf..3a0484683cd6 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -65,6 +65,7 @@ enum pm_domain {
enum camss_version {
CAMSS_8x16,
CAMSS_8x96,
+ CAMSS_660,
};
struct camss {
diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c
index 6103aaf43987..bdd293faaad0 100644
--- a/drivers/media/platform/qcom/venus/core.c
+++ b/drivers/media/platform/qcom/venus/core.c
@@ -345,6 +345,14 @@ static int venus_remove(struct platform_device *pdev)
return ret;
}
+static void venus_core_shutdown(struct platform_device *pdev)
+{
+ struct venus_core *core = platform_get_drvdata(pdev);
+
+ venus_shutdown(core);
+ venus_firmware_deinit(core);
+}
+
static __maybe_unused int venus_runtime_suspend(struct device *dev)
{
struct venus_core *core = dev_get_drvdata(dev);
@@ -355,12 +363,26 @@ static __maybe_unused int venus_runtime_suspend(struct device *dev)
if (ret)
return ret;
+ if (pm_ops->core_power) {
+ ret = pm_ops->core_power(dev, POWER_OFF);
+ if (ret)
+ return ret;
+ }
+
ret = icc_set_bw(core->cpucfg_path, 0, 0);
if (ret)
- return ret;
+ goto err_cpucfg_path;
- if (pm_ops->core_power)
- ret = pm_ops->core_power(dev, POWER_OFF);
+ ret = icc_set_bw(core->video_path, 0, 0);
+ if (ret)
+ goto err_video_path;
+
+ return ret;
+
+err_video_path:
+ icc_set_bw(core->cpucfg_path, kbps_to_icc(1000), 0);
+err_cpucfg_path:
+ pm_ops->core_power(dev, POWER_ON);
return ret;
}
@@ -371,16 +393,20 @@ static __maybe_unused int venus_runtime_resume(struct device *dev)
const struct venus_pm_ops *pm_ops = core->pm_ops;
int ret;
+ ret = icc_set_bw(core->video_path, kbps_to_icc(20000), 0);
+ if (ret)
+ return ret;
+
+ ret = icc_set_bw(core->cpucfg_path, kbps_to_icc(1000), 0);
+ if (ret)
+ return ret;
+
if (pm_ops->core_power) {
ret = pm_ops->core_power(dev, POWER_ON);
if (ret)
return ret;
}
- ret = icc_set_bw(core->cpucfg_path, 0, kbps_to_icc(1000));
- if (ret)
- return ret;
-
return hfi_core_resume(core, false);
}
@@ -602,6 +628,7 @@ static struct platform_driver qcom_venus_driver = {
.of_match_table = venus_dt_match,
.pm = &venus_pm_ops,
},
+ .shutdown = venus_core_shutdown,
};
module_platform_driver(qcom_venus_driver);
diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h
index 7b79a33dc9d6..f03ed427accd 100644
--- a/drivers/media/platform/qcom/venus/core.h
+++ b/drivers/media/platform/qcom/venus/core.h
@@ -243,8 +243,19 @@ struct venc_controls {
u32 header_mode;
- u32 profile;
- u32 level;
+ struct {
+ u32 h264;
+ u32 mpeg4;
+ u32 hevc;
+ u32 vp8;
+ u32 vp9;
+ } profile;
+ struct {
+ u32 h264;
+ u32 mpeg4;
+ u32 hevc;
+ u32 vp9;
+ } level;
};
struct venus_buffer {
@@ -361,6 +372,7 @@ struct venus_inst {
unsigned int streamon_cap, streamon_out;
u32 width;
u32 height;
+ struct v4l2_rect crop;
u32 out_width;
u32 out_height;
u32 colorspace;
diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c
index 1db64a854b88..d03e2dd5808c 100644
--- a/drivers/media/platform/qcom/venus/firmware.c
+++ b/drivers/media/platform/qcom/venus/firmware.c
@@ -171,9 +171,14 @@ static int venus_shutdown_no_tz(struct venus_core *core)
iommu = core->fw.iommu_domain;
- unmapped = iommu_unmap(iommu, VENUS_FW_START_ADDR, mapped);
- if (unmapped != mapped)
- dev_err(dev, "failed to unmap firmware\n");
+ if (core->fw.mapped_mem_size && iommu) {
+ unmapped = iommu_unmap(iommu, VENUS_FW_START_ADDR, mapped);
+
+ if (unmapped != mapped)
+ dev_err(dev, "failed to unmap firmware\n");
+ else
+ core->fw.mapped_mem_size = 0;
+ }
return 0;
}
@@ -305,7 +310,11 @@ void venus_firmware_deinit(struct venus_core *core)
iommu = core->fw.iommu_domain;
iommu_detach_device(iommu, core->fw.dev);
- iommu_domain_free(iommu);
+
+ if (core->fw.iommu_domain) {
+ iommu_domain_free(iommu);
+ core->fw.iommu_domain = NULL;
+ }
platform_device_unregister(to_platform_device(core->fw.dev));
}
diff --git a/drivers/media/platform/qcom/venus/hfi.c b/drivers/media/platform/qcom/venus/hfi.c
index a59022adb14c..638ed5cfe05e 100644
--- a/drivers/media/platform/qcom/venus/hfi.c
+++ b/drivers/media/platform/qcom/venus/hfi.c
@@ -198,6 +198,18 @@ int hfi_session_init(struct venus_inst *inst, u32 pixfmt)
const struct hfi_ops *ops = core->ops;
int ret;
+ /*
+ * If core shutdown is in progress or if we are in system
+ * recovery, return an error as during system error recovery
+ * session_init() can't pass successfully
+ */
+ mutex_lock(&core->lock);
+ if (!core->ops || core->sys_error) {
+ mutex_unlock(&core->lock);
+ return -EIO;
+ }
+ mutex_unlock(&core->lock);
+
if (inst->state != INST_UNINIT)
return -EINVAL;
diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c
index 57877eacecf0..a3850261d697 100644
--- a/drivers/media/platform/qcom/venus/pm_helpers.c
+++ b/drivers/media/platform/qcom/venus/pm_helpers.c
@@ -212,6 +212,16 @@ static int load_scale_bw(struct venus_core *core)
}
mutex_unlock(&core->lock);
+ /*
+ * keep minimum bandwidth vote for "video-mem" path,
+ * so that clks can be disabled during vdec_session_release().
+ * Actual bandwidth drop will be done during device supend
+ * so that device can power down without any warnings.
+ */
+
+ if (!total_avg && !total_peak)
+ total_avg = kbps_to_icc(1000);
+
dev_dbg(core->dev, VDBGL "total: avg_bw: %u, peak_bw: %u\n",
total_avg, total_peak);
@@ -794,7 +804,7 @@ skip_pmdomains:
return 0;
opp_dl_add_err:
- dev_pm_domain_detach(core->opp_pmdomain, true);
+ dev_pm_opp_detach_genpd(core->opp_table);
opp_attach_err:
if (core->pd_dl_venus) {
device_link_del(core->pd_dl_venus);
@@ -832,7 +842,7 @@ skip_pmdomains:
if (core->opp_dl_venus)
device_link_del(core->opp_dl_venus);
- dev_pm_domain_detach(core->opp_pmdomain, true);
+ dev_pm_opp_detach_genpd(core->opp_table);
}
static int core_get_v4(struct device *dev)
@@ -898,8 +908,7 @@ static void core_put_v4(struct device *dev)
if (core->has_opp_table)
dev_pm_opp_of_remove_table(dev);
- if (core->opp_table)
- dev_pm_opp_put_clkname(core->opp_table);
+ dev_pm_opp_put_clkname(core->opp_table);
}
@@ -928,7 +937,7 @@ static unsigned long calculate_inst_freq(struct venus_inst *inst,
u32 fps = (u32)inst->fps;
u32 mbs_per_sec;
- mbs_per_sec = load_per_instance(inst) / fps;
+ mbs_per_sec = load_per_instance(inst);
vpp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vpp_freq;
/* 21 / 20 is overhead factor */
diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c
index ea13170a6a2c..8488411204c3 100644
--- a/drivers/media/platform/qcom/venus/vdec.c
+++ b/drivers/media/platform/qcom/venus/vdec.c
@@ -325,6 +325,10 @@ static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
inst->width = format.fmt.pix_mp.width;
inst->height = format.fmt.pix_mp.height;
+ inst->crop.top = 0;
+ inst->crop.left = 0;
+ inst->crop.width = inst->width;
+ inst->crop.height = inst->height;
if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
inst->fmt_out = fmt;
@@ -343,6 +347,9 @@ vdec_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
return -EINVAL;
+ s->r.top = 0;
+ s->r.left = 0;
+
switch (s->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
case V4L2_SEL_TGT_CROP_DEFAULT:
@@ -363,16 +370,12 @@ vdec_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
case V4L2_SEL_TGT_COMPOSE:
if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- s->r.width = inst->out_width;
- s->r.height = inst->out_height;
+ s->r = inst->crop;
break;
default:
return -EINVAL;
}
- s->r.top = 0;
- s->r.left = 0;
-
return 0;
}
@@ -1309,6 +1312,21 @@ static void vdec_event_change(struct venus_inst *inst,
inst->width = format.fmt.pix_mp.width;
inst->height = format.fmt.pix_mp.height;
+ /*
+ * Some versions of the firmware do not report crop information for
+ * all codecs. For these cases, set the crop to the coded resolution.
+ */
+ if (ev_data->input_crop.width > 0 && ev_data->input_crop.height > 0) {
+ inst->crop.left = ev_data->input_crop.left;
+ inst->crop.top = ev_data->input_crop.top;
+ inst->crop.width = ev_data->input_crop.width;
+ inst->crop.height = ev_data->input_crop.height;
+ } else {
+ inst->crop.left = 0;
+ inst->crop.top = 0;
+ inst->crop.width = ev_data->width;
+ inst->crop.height = ev_data->height;
+ }
inst->out_width = ev_data->width;
inst->out_height = ev_data->height;
@@ -1412,6 +1430,10 @@ static void vdec_inst_init(struct venus_inst *inst)
inst->fmt_cap = &vdec_formats[0];
inst->width = frame_width_min(inst);
inst->height = ALIGN(frame_height_min(inst), 32);
+ inst->crop.left = 0;
+ inst->crop.top = 0;
+ inst->crop.width = inst->width;
+ inst->crop.height = inst->height;
inst->out_width = frame_width_min(inst);
inst->out_height = frame_height_min(inst);
inst->fps = 30;
diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c
index f8b1484e7dcd..1c61602c5de1 100644
--- a/drivers/media/platform/qcom/venus/venc.c
+++ b/drivers/media/platform/qcom/venus/venc.c
@@ -537,6 +537,7 @@ static int venc_set_properties(struct venus_inst *inst)
struct hfi_quantization quant;
struct hfi_quantization_range quant_range;
u32 ptype, rate_control, bitrate;
+ u32 profile, level;
int ret;
ret = venus_helper_set_work_mode(inst, VIDC_WORK_MODE_2);
@@ -684,7 +685,35 @@ static int venc_set_properties(struct venus_inst *inst)
if (ret)
return ret;
- ret = venus_helper_set_profile_level(inst, ctr->profile, ctr->level);
+ switch (inst->hfi_codec) {
+ case HFI_VIDEO_CODEC_H264:
+ profile = ctr->profile.h264;
+ level = ctr->level.h264;
+ break;
+ case HFI_VIDEO_CODEC_MPEG4:
+ profile = ctr->profile.mpeg4;
+ level = ctr->level.mpeg4;
+ break;
+ case HFI_VIDEO_CODEC_VP8:
+ profile = ctr->profile.vp8;
+ level = 0;
+ break;
+ case HFI_VIDEO_CODEC_VP9:
+ profile = ctr->profile.vp9;
+ level = ctr->level.vp9;
+ break;
+ case HFI_VIDEO_CODEC_HEVC:
+ profile = ctr->profile.hevc;
+ level = ctr->level.hevc;
+ break;
+ case HFI_VIDEO_CODEC_MPEG2:
+ default:
+ profile = 0;
+ level = 0;
+ break;
+ }
+
+ ret = venus_helper_set_profile_level(inst, profile, level);
if (ret)
return ret;
@@ -999,7 +1028,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
static void venc_inst_init(struct venus_inst *inst)
{
- inst->fmt_cap = &venc_formats[2];
+ inst->fmt_cap = &venc_formats[3];
inst->fmt_out = &venc_formats[0];
inst->width = 1280;
inst->height = ALIGN(720, 32);
diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c
index 0708b3b89d0c..cf860e6446c0 100644
--- a/drivers/media/platform/qcom/venus/venc_ctrls.c
+++ b/drivers/media/platform/qcom/venus/venc_ctrls.c
@@ -103,15 +103,25 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
ctr->h264_entropy_mode = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+ ctr->profile.mpeg4 = ctrl->val;
+ break;
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ ctr->profile.h264 = ctrl->val;
+ break;
case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
+ ctr->profile.hevc = ctrl->val;
+ break;
case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
- ctr->profile = ctrl->val;
+ ctr->profile.vp8 = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+ ctr->level.mpeg4 = ctrl->val;
+ break;
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ ctr->level.h264 = ctrl->val;
+ break;
case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
- ctr->level = ctrl->val;
+ ctr->level.hevc = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
ctr->h264_i_qp = ctrl->val;