diff options
Diffstat (limited to 'drivers/media/platform/qcom')
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; |