diff options
Diffstat (limited to 'drivers/media/platform/qcom')
29 files changed, 1813 insertions, 195 deletions
diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile index f6db5b3b5ace..d26a9c24a430 100644 --- a/drivers/media/platform/qcom/camss/Makefile +++ b/drivers/media/platform/qcom/camss/Makefile @@ -6,6 +6,7 @@ qcom-camss-objs += \ camss-csid.o \ camss-csid-4-1.o \ camss-csid-4-7.o \ + camss-csid-680.o \ camss-csid-gen2.o \ camss-csid-780.o \ camss-csiphy-2ph-1-0.o \ @@ -17,6 +18,7 @@ qcom-camss-objs += \ camss-vfe-4-8.o \ camss-vfe-17x.o \ camss-vfe-480.o \ + camss-vfe-680.o \ camss-vfe-780.o \ camss-vfe-gen1.o \ camss-vfe.o \ diff --git a/drivers/media/platform/qcom/camss/camss-csid-680.c b/drivers/media/platform/qcom/camss/camss-csid-680.c new file mode 100644 index 000000000000..3ad3a174bcfb --- /dev/null +++ b/drivers/media/platform/qcom/camss/camss-csid-680.c @@ -0,0 +1,422 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module + * + * Copyright (C) 2020-2025 Linaro Ltd. + */ +#include <linux/completion.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> + +#include "camss.h" +#include "camss-csid.h" +#include "camss-csid-gen2.h" + +#define CSID_TOP_IO_PATH_CFG0(csid) (0x4 * (csid)) +#define CSID_TOP_IO_PATH_CFG0_INTERNAL_CSID BIT(0) +#define CSID_TOP_IO_PATH_CFG0_SFE_0 BIT(1) +#define CSID_TOP_IO_PATH_CFG0_SFE_1 GENMASK(1, 0) +#define CSID_TOP_IO_PATH_CFG0_SBI_0 BIT(4) +#define CSID_TOP_IO_PATH_CFG0_SBI_1 GENMASK(3, 0) +#define CSID_TOP_IO_PATH_CFG0_SBI_2 GENMASK(3, 1) +#define CSID_TOP_IO_PATH_CFG0_OUTPUT_IFE_EN BIT(8) +#define CSID_TOP_IO_PATH_CFG0_SFE_OFFLINE_EN BIT(12) + +#define CSID_RESET_CMD 0x10 +#define CSID_RESET_CMD_HW_RESET BIT(0) +#define CSID_RESET_CMD_SW_RESET BIT(1) +#define CSID_RESET_CMD_IRQ_CTRL BIT(2) + +#define CSID_IRQ_CMD 0x14 +#define CSID_IRQ_CMD_CLEAR BIT(0) +#define CSID_IRQ_CMD_SET BIT(4) + +#define CSID_REG_UPDATE_CMD 0x18 + +#define CSID_CSI2_RDIN_IRQ_STATUS(rdi) (0xec + 0x10 * (rdi)) +#define CSID_CSI2_RDIN_CCIF_VIOLATION BIT(29) +#define CSID_CSI2_RDIN_SENSOR_SWITCH_OUT_OF_SYNC_FRAME_DROP BIT(28) +#define CSID_CSI2_RDIN_ERROR_REC_WIDTH_VIOLATION BIT(27) +#define CSID_CSI2_RDIN_ERROR_REC_HEIGHT_VIOLATION BIT(26) +#define CSID_CSI2_RDIN_BATCH_END_MISSING_VIOLATION BIT(25) +#define CSID_CSI2_RDIN_ILLEGAL_BATCH_ID_IRQ BIT(24) +#define CSID_CSI2_RDIN_RUP_DONE BIT(23) +#define CSID_CSI2_RDIN_CAMIF_EPOCH_1_IRQ BIT(22) +#define CSID_CSI2_RDIN_CAMIF_EPOCH_0_IRQ BIT(21) +#define CSID_CSI2_RDIN_ERROR_REC_OVERFLOW_IRQ BIT(19) +#define CSID_CSI2_RDIN_ERROR_REC_FRAME_DROP BIT(18) +#define CSID_CSI2_RDIN_VCDT_GRP_CHANG BIT(17) +#define CSID_CSI2_RDIN_VCDT_GRP_0_SEL BIT(16) +#define CSID_CSI2_RDIN_VCDT_GRP_1_SEL BIT(15) +#define CSID_CSI2_RDIN_ERROR_LINE_COUNT BIT(14) +#define CSID_CSI2_RDIN_ERROR_PIX_COUNT BIT(13) +#define CSID_CSI2_RDIN_INFO_INPUT_SOF BIT(12) +#define CSID_CSI2_RDIN_INFO_INPUT_SOL BIT(11) +#define CSID_CSI2_RDIN_INFO_INPUT_EOL BIT(10) +#define CSID_CSI2_RDIN_INFO_INPUT_EOF BIT(9) +#define CSID_CSI2_RDIN_INFO_FRAME_DROP_SOF BIT(8) +#define CSID_CSI2_RDIN_INFO_FRAME_DROP_SOL BIT(7) +#define CSID_CSI2_RDIN_INFO_FRAME_DROP_EOL BIT(6) +#define CSID_CSI2_RDIN_INFO_FRAME_DROP_EOF BIT(5) +#define CSID_CSI2_RDIN_INFO_CAMIF_SOF BIT(4) +#define CSID_CSI2_RDIN_INFO_CAMIF_EOF BIT(3) +#define CSID_CSI2_RDIN_INFO_FIFO_OVERFLOW BIT(2) +#define CSID_CSI2_RDIN_RES1 BIT(1) +#define CSID_CSI2_RDIN_RES0 BIT(0) + +#define CSID_CSI2_RDIN_IRQ_MASK(rdi) (0xf0 + 0x10 * (rdi)) +#define CSID_CSI2_RDIN_IRQ_CLEAR(rdi) (0xf4 + 0x10 * (rdi)) +#define CSID_CSI2_RDIN_IRQ_SET(rdi) (0xf8 + 0x10 * (rdi)) + +#define CSID_TOP_IRQ_STATUS 0x7c +#define CSID_TOP_IRQ_MASK 0x80 +#define CSID_TOP_IRQ_CLEAR 0x84 +#define CSID_TOP_IRQ_RESET BIT(0) +#define CSID_TOP_IRQ_RX BIT(2) +#define CSID_TOP_IRQ_LONG_PKT(rdi) (BIT(8) << (rdi)) +#define CSID_TOP_IRQ_BUF_DONE BIT(13) + +#define CSID_BUF_DONE_IRQ_STATUS 0x8c +#define BUF_DONE_IRQ_STATUS_RDI_OFFSET (csid_is_lite(csid) ? 1 : 14) +#define CSID_BUF_DONE_IRQ_MASK 0x90 +#define CSID_BUF_DONE_IRQ_CLEAR 0x94 + +#define CSID_CSI2_RX_IRQ_STATUS 0x9c +#define CSID_CSI2_RX_IRQ_MASK 0xa0 +#define CSID_CSI2_RX_IRQ_CLEAR 0xa4 + +#define CSID_RESET_CFG 0xc +#define CSID_RESET_CFG_MODE_IMMEDIATE BIT(0) +#define CSID_RESET_CFG_LOCATION_COMPLETE BIT(4) + +#define CSID_CSI2_RDI_IRQ_STATUS(rdi) (0xec + 0x10 * (rdi)) +#define CSID_CSI2_RDI_IRQ_MASK(rdi) (0xf0 + 0x10 * (rdi)) +#define CSID_CSI2_RDI_IRQ_CLEAR(rdi) (0xf4 + 0x10 * (rdi)) + +#define CSID_CSI2_RX_CFG0 0x200 +#define CSI2_RX_CFG0_NUM_ACTIVE_LANES 0 +#define CSI2_RX_CFG0_DL0_INPUT_SEL 4 +#define CSI2_RX_CFG0_DL1_INPUT_SEL 8 +#define CSI2_RX_CFG0_DL2_INPUT_SEL 12 +#define CSI2_RX_CFG0_DL3_INPUT_SEL 16 +#define CSI2_RX_CFG0_PHY_NUM_SEL 20 +#define CSI2_RX_CFG0_PHY_SEL_BASE_IDX 1 +#define CSI2_RX_CFG0_PHY_TYPE_SEL 24 + +#define CSID_CSI2_RX_CFG1 0x204 +#define CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN BIT(0) +#define CSI2_RX_CFG1_DE_SCRAMBLE_EN BIT(1) +#define CSI2_RX_CFG1_VC_MODE BIT(2) +#define CSI2_RX_CFG1_COMPLETE_STREAM_EN BIT(4) +#define CSI2_RX_CFG1_COMPLETE_STREAM_FRAME_TIMING BIT(5) +#define CSI2_RX_CFG1_MISR_EN BIT(6) +#define CSI2_RX_CFG1_CGC_MODE BIT(7) + +#define CSID_CSI2_RX_CAPTURE_CTRL 0x208 +#define CSI2_RX_CAPTURE_CTRL_LONG_PKT_EN BIT(0) +#define CSI2_RX_CAPTURE_CTRL_SHORT_PKT_EN BIT(1) +#define CSI2_RX_CAPTURE_CTRL_CPHY_PKT_EN BIT(2) +#define CSI2_RX_CAPTURE_CTRL_LONG_PKT_DT GENMASK(9, 4) +#define CSI2_RX_CAPTURE_CTRL_LONG_PKT_VC GENMASK(14, 10) +#define CSI2_RX_CAPTURE_CTRL_SHORT_PKT_VC GENMASK(19, 15) +#define CSI2_RX_CAPTURE_CTRL_CPHY_PKT_DT GENMASK(20, 25) +#define CSI2_RX_CAPTURE_CTRL_CPHY_PKT_VC GENMASK(30, 26) + +#define CSID_CSI2_RX_TOTAL_PKTS_RCVD 0x240 +#define CSID_CSI2_RX_STATS_ECC 0x244 +#define CSID_CSI2_RX_CRC_ERRORS 0x248 + +#define CSID_RDI_CFG0(rdi) (0x500 + 0x100 * (rdi)) +#define RDI_CFG0_DECODE_FORMAT 12 +#define RDI_CFG0_DATA_TYPE 16 +#define RDI_CFG0_VIRTUAL_CHANNEL 22 +#define RDI_CFG0_DT_ID 27 +#define RDI_CFG0_ENABLE BIT(31) + +#define CSID_RDI_CTRL(rdi) (0x504 + 0x100 * (rdi)) +#define CSID_RDI_CTRL_HALT_CMD_HALT_AT_FRAME_BOUNDARY 0 +#define CSID_RDI_CTRL_HALT_CMD_RESUME_AT_FRAME_BOUNDARY 1 + +#define CSID_RDI_CFG1(rdi) (0x510 + 0x100 * (rdi)) +#define RDI_CFG1_TIMESTAMP_STB_FRAME BIT(0) +#define RDI_CFG1_TIMESTAMP_STB_IRQ BIT(1) +#define RDI_CFG1_BYTE_CNTR_EN BIT(2) +#define RDI_CFG1_TIMESTAMP_EN BIT(4) +#define RDI_CFG1_DROP_H_EN BIT(5) +#define RDI_CFG1_DROP_V_EN BIT(6) +#define RDI_CFG1_CROP_H_EN BIT(7) +#define RDI_CFG1_CROP_V_EN BIT(8) +#define RDI_CFG1_MISR_EN BIT(9) +#define RDI_CFG1_PLAIN_ALIGN_MSB BIT(11) +#define RDI_CFG1_EARLY_EOF_EN BIT(14) +#define RDI_CFG1_PACKING_MIPI BIT(15) + +#define CSID_RDI_ERR_RECOVERY_CFG0(rdi) (0x514 + 0x100 * (rdi)) +#define CSID_RDI_EPOCH_IRQ_CFG(rdi) (0x52c + 0x100 * (rdi)) +#define CSID_RDI_FRM_DROP_PATTERN(rdi) (0x540 + 0x100 * (rdi)) +#define CSID_RDI_FRM_DROP_PERIOD(rdi) (0x544 + 0x100 * (rdi)) +#define CSID_RDI_IRQ_SUBSAMPLE_PATTERN(rdi) (0x548 + 0x100 * (rdi)) +#define CSID_RDI_IRQ_SUBSAMPLE_PERIOD(rdi) (0x54c + 0x100 * (rdi)) +#define CSID_RDI_PIX_DROP_PATTERN(rdi) (0x558 + 0x100 * (rdi)) +#define CSID_RDI_PIX_DROP_PERIOD(rdi) (0x55c + 0x100 * (rdi)) +#define CSID_RDI_LINE_DROP_PATTERN(rdi) (0x560 + 0x100 * (rdi)) +#define CSID_RDI_LINE_DROP_PERIOD(rdi) (0x564 + 0x100 * (rdi)) + +static inline int reg_update_rdi(struct csid_device *csid, int n) +{ + return BIT(4 + n) + BIT(20 + n); +} + +static void csid_reg_update(struct csid_device *csid, int port_id) +{ + csid->reg_update |= reg_update_rdi(csid, port_id); + writel(csid->reg_update, csid->base + CSID_REG_UPDATE_CMD); +} + +static inline void csid_reg_update_clear(struct csid_device *csid, + int port_id) +{ + csid->reg_update &= ~reg_update_rdi(csid, port_id); + writel(csid->reg_update, csid->base + CSID_REG_UPDATE_CMD); +} + +static void __csid_configure_rx(struct csid_device *csid, + struct csid_phy_config *phy, int vc) +{ + u32 val; + + val = (phy->lane_cnt - 1) << CSI2_RX_CFG0_NUM_ACTIVE_LANES; + val |= phy->lane_assign << CSI2_RX_CFG0_DL0_INPUT_SEL; + val |= (phy->csiphy_id + CSI2_RX_CFG0_PHY_SEL_BASE_IDX) << CSI2_RX_CFG0_PHY_NUM_SEL; + + writel(val, csid->base + CSID_CSI2_RX_CFG0); + + val = CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN; + if (vc > 3) + val |= CSI2_RX_CFG1_VC_MODE; + writel(val, csid->base + CSID_CSI2_RX_CFG1); +} + +static void __csid_ctrl_rdi(struct csid_device *csid, int enable, u8 rdi) +{ + u32 val; + + if (enable) + val = CSID_RDI_CTRL_HALT_CMD_RESUME_AT_FRAME_BOUNDARY; + else + val = CSID_RDI_CTRL_HALT_CMD_HALT_AT_FRAME_BOUNDARY; + + writel(val, csid->base + CSID_RDI_CTRL(rdi)); +} + +static void __csid_configure_top(struct csid_device *csid) +{ + u32 val; + + val = CSID_TOP_IO_PATH_CFG0_OUTPUT_IFE_EN | CSID_TOP_IO_PATH_CFG0_INTERNAL_CSID; + writel(val, csid->camss->csid_wrapper_base + + CSID_TOP_IO_PATH_CFG0(csid->id)); +} + +static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 vc) +{ + struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; + const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats, + csid->res->formats->nformats, + input_format->code); + u8 lane_cnt = csid->phy.lane_cnt; + u8 dt_id; + u32 val; + + if (!lane_cnt) + lane_cnt = 4; + + val = 0; + writel(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(vc)); + + /* + * DT_ID is a two bit bitfield that is concatenated with + * the four least significant bits of the five bit VC + * bitfield to generate an internal CID value. + * + * CSID_RDI_CFG0(vc) + * DT_ID : 28:27 + * VC : 26:22 + * DT : 21:16 + * + * CID : VC 3:0 << 2 | DT_ID 1:0 + */ + dt_id = vc & 0x03; + + /* note: for non-RDI path, this should be format->decode_format */ + val |= DECODE_FORMAT_PAYLOAD_ONLY << RDI_CFG0_DECODE_FORMAT; + val |= format->data_type << RDI_CFG0_DATA_TYPE; + val |= vc << RDI_CFG0_VIRTUAL_CHANNEL; + val |= dt_id << RDI_CFG0_DT_ID; + writel(val, csid->base + CSID_RDI_CFG0(vc)); + + val = RDI_CFG1_TIMESTAMP_STB_FRAME; + val |= RDI_CFG1_BYTE_CNTR_EN; + val |= RDI_CFG1_TIMESTAMP_EN; + val |= RDI_CFG1_DROP_H_EN; + val |= RDI_CFG1_DROP_V_EN; + val |= RDI_CFG1_CROP_H_EN; + val |= RDI_CFG1_CROP_V_EN; + val |= RDI_CFG1_PACKING_MIPI; + + writel(val, csid->base + CSID_RDI_CFG1(vc)); + + val = 0; + writel(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(vc)); + + val = 1; + writel(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(vc)); + + val = 0; + writel(val, csid->base + CSID_RDI_CTRL(vc)); + + val = readl(csid->base + CSID_RDI_CFG0(vc)); + if (enable) + val |= RDI_CFG0_ENABLE; + else + val &= ~RDI_CFG0_ENABLE; + writel(val, csid->base + CSID_RDI_CFG0(vc)); +} + +static void csid_configure_stream(struct csid_device *csid, u8 enable) +{ + int i; + + __csid_configure_top(csid); + + /* Loop through all enabled VCs and configure stream for each */ + for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++) { + if (csid->phy.en_vc & BIT(i)) { + __csid_configure_rdi_stream(csid, enable, i); + __csid_configure_rx(csid, &csid->phy, i); + __csid_ctrl_rdi(csid, enable, i); + } + } +} + +/* + * csid_reset - Trigger reset on CSID module and wait to complete + * @csid: CSID device + * + * Return 0 on success or a negative error code otherwise + */ +static int csid_reset(struct csid_device *csid) +{ + unsigned long time; + u32 val; + int i; + + reinit_completion(&csid->reset_complete); + + writel(CSID_IRQ_CMD_CLEAR, csid->base + CSID_IRQ_CMD); + + /* preserve registers */ + val = CSID_RESET_CFG_MODE_IMMEDIATE | CSID_RESET_CFG_LOCATION_COMPLETE; + writel(val, csid->base + CSID_RESET_CFG); + + val = CSID_RESET_CMD_HW_RESET | CSID_RESET_CMD_SW_RESET; + writel(val, csid->base + CSID_RESET_CMD); + + time = wait_for_completion_timeout(&csid->reset_complete, + msecs_to_jiffies(CSID_RESET_TIMEOUT_MS)); + if (!time) { + dev_err(csid->camss->dev, "CSID reset timeout\n"); + return -EIO; + } + + for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++) { + /* Enable RUP done for the client port */ + writel(CSID_CSI2_RDIN_RUP_DONE, csid->base + CSID_CSI2_RDIN_IRQ_MASK(i)); + } + + /* Clear RDI status */ + writel(~0u, csid->base + CSID_BUF_DONE_IRQ_CLEAR); + + /* Enable BUF_DONE bit for all write-master client ports */ + writel(~0u, csid->base + CSID_BUF_DONE_IRQ_MASK); + + /* Unmask all TOP interrupts */ + writel(~0u, csid->base + CSID_TOP_IRQ_MASK); + + return 0; +} + +static void csid_rup_complete(struct csid_device *csid, int rdi) +{ + csid_reg_update_clear(csid, rdi); +} + +/* + * csid_isr - CSID module interrupt service routine + * @irq: Interrupt line + * @dev: CSID device + * + * Return IRQ_HANDLED on success + */ +static irqreturn_t csid_isr(int irq, void *dev) +{ + struct csid_device *csid = dev; + u32 buf_done_val, val, val_top; + int i; + + /* Latch and clear TOP status */ + val_top = readl(csid->base + CSID_TOP_IRQ_STATUS); + writel(val_top, csid->base + CSID_TOP_IRQ_CLEAR); + + /* Latch and clear CSID_CSI2 status */ + val = readl(csid->base + CSID_CSI2_RX_IRQ_STATUS); + writel(val, csid->base + CSID_CSI2_RX_IRQ_CLEAR); + + /* Latch and clear top level BUF_DONE status */ + buf_done_val = readl(csid->base + CSID_BUF_DONE_IRQ_STATUS); + writel(buf_done_val, csid->base + CSID_BUF_DONE_IRQ_CLEAR); + + /* Process state for each RDI channel */ + for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++) { + val = readl(csid->base + CSID_CSI2_RDIN_IRQ_STATUS(i)); + if (val) + writel(val, csid->base + CSID_CSI2_RDIN_IRQ_CLEAR(i)); + + if (val & CSID_CSI2_RDIN_RUP_DONE) + csid_rup_complete(csid, i); + + if (buf_done_val & BIT(BUF_DONE_IRQ_STATUS_RDI_OFFSET + i)) + camss_buf_done(csid->camss, csid->id, i); + } + + /* Issue clear command */ + writel(CSID_IRQ_CMD_CLEAR, csid->base + CSID_IRQ_CMD); + + /* Reset complete */ + if (val_top & CSID_TOP_IRQ_RESET) + complete(&csid->reset_complete); + + return IRQ_HANDLED; +} + +static void csid_subdev_reg_update(struct csid_device *csid, int port_id, bool is_clear) +{ + if (is_clear) + csid_reg_update_clear(csid, port_id); + else + csid_reg_update(csid, port_id); +} + +static void csid_subdev_init(struct csid_device *csid) {} + +const struct csid_hw_ops csid_ops_680 = { + .configure_testgen_pattern = NULL, + .configure_stream = csid_configure_stream, + .hw_version = csid_hw_version, + .isr = csid_isr, + .reset = csid_reset, + .src_pad_code = csid_src_pad_code, + .subdev_init = csid_subdev_init, + .reg_update = csid_subdev_reg_update, +}; diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index d08117f46f3b..5284b5857368 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -613,8 +613,8 @@ u32 csid_hw_version(struct csid_device *csid) hw_gen = (hw_version >> HW_VERSION_GENERATION) & 0xF; hw_rev = (hw_version >> HW_VERSION_REVISION) & 0xFFF; hw_step = (hw_version >> HW_VERSION_STEPPING) & 0xFFFF; - dev_info(csid->camss->dev, "CSID:%d HW Version = %u.%u.%u\n", - csid->id, hw_gen, hw_rev, hw_step); + dev_dbg(csid->camss->dev, "CSID:%d HW Version = %u.%u.%u\n", + csid->id, hw_gen, hw_rev, hw_step); return hw_version; } diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h index 90b8fc5852be..9dc826d8c8f6 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.h +++ b/drivers/media/platform/qcom/camss/camss-csid.h @@ -213,6 +213,7 @@ extern const struct csid_formats csid_formats_gen2; extern const struct csid_hw_ops csid_ops_4_1; extern const struct csid_hw_ops csid_ops_4_7; +extern const struct csid_hw_ops csid_ops_680; extern const struct csid_hw_ops csid_ops_gen2; extern const struct csid_hw_ops csid_ops_780; 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 a6cc957b986e..f732a76de93e 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 @@ -55,11 +55,12 @@ #define CSIPHY_DNP_PARAMS 4 #define CSIPHY_2PH_REGS 5 #define CSIPHY_3PH_REGS 6 +#define CSIPHY_SKEW_CAL 7 struct csiphy_lane_regs { s32 reg_addr; s32 reg_data; - s32 delay; + u32 delay_us; u32 csiphy_param_type; }; @@ -423,6 +424,123 @@ csiphy_lane_regs lane_regs_sm8550[] = { {0x0C64, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, }; +/* 4nm 2PH v 2.1.2 2p5Gbps 4 lane DPHY mode */ +static const struct +csiphy_lane_regs lane_regs_x1e80100[] = { + /* Power up lanes 2ph mode */ + {0x1014, 0xD5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x101C, 0x7A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x1018, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + + {0x0094, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x00A0, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0090, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0098, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0094, 0x07, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x8E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0094, 0xD7, 0x00, CSIPHY_SKEW_CAL}, + {0x005C, 0x00, 0x00, CSIPHY_SKEW_CAL}, + {0x0060, 0xBD, 0x00, CSIPHY_SKEW_CAL}, + {0x0064, 0x7F, 0x00, CSIPHY_SKEW_CAL}, + + {0x0E94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0EA0, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0E90, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0E98, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0E94, 0x07, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0E30, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0E28, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0E00, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0E0C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0E38, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0E2C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0E34, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0E1C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0E14, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0E3C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0E04, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0E20, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0E08, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0E10, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + + {0x0494, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x04A0, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0490, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0498, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0494, 0x07, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x8E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0494, 0xD7, 0x00, CSIPHY_SKEW_CAL}, + {0x045C, 0x00, 0x00, CSIPHY_SKEW_CAL}, + {0x0460, 0xBD, 0x00, CSIPHY_SKEW_CAL}, + {0x0464, 0x7F, 0x00, CSIPHY_SKEW_CAL}, + + {0x0894, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x08A0, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0890, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0898, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0894, 0x07, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0830, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x8E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0838, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x082C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0834, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0814, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x083C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0804, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0820, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0808, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0810, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0894, 0xD7, 0x00, CSIPHY_SKEW_CAL}, + {0x085C, 0x00, 0x00, CSIPHY_SKEW_CAL}, + {0x0860, 0xBD, 0x00, CSIPHY_SKEW_CAL}, + {0x0864, 0x7F, 0x00, CSIPHY_SKEW_CAL}, + + {0x0C94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0CA0, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C90, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C98, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C94, 0x07, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0C30, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C00, 0x8E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C38, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C2C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C34, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C1C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C14, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C3C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C20, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C08, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0C10, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C94, 0xD7, 0x00, CSIPHY_SKEW_CAL}, + {0x0C5C, 0x00, 0x00, CSIPHY_SKEW_CAL}, + {0x0C60, 0xBD, 0x00, CSIPHY_SKEW_CAL}, + {0x0C64, 0x7F, 0x00, CSIPHY_SKEW_CAL}, +}; + static void csiphy_hw_version_read(struct csiphy_device *csiphy, struct device *dev) { @@ -593,6 +711,9 @@ static void csiphy_gen2_config_lanes(struct csiphy_device *csiphy, case CSIPHY_SETTLE_CNT_LOWER_BYTE: val = settle_cnt & 0xff; break; + case CSIPHY_SKEW_CAL: + /* TODO: support application of skew from dt flag */ + continue; case CSIPHY_DNP_PARAMS: continue; default: @@ -600,6 +721,8 @@ static void csiphy_gen2_config_lanes(struct csiphy_device *csiphy, break; } writel_relaxed(val, csiphy->base + r->reg_addr); + if (r->delay_us) + udelay(r->delay_us); } } @@ -626,6 +749,7 @@ static bool csiphy_is_gen2(u32 version) case CAMSS_8280XP: case CAMSS_845: case CAMSS_8550: + case CAMSS_X1E80100: ret = true; break; } @@ -714,6 +838,11 @@ static int csiphy_init(struct csiphy_device *csiphy) regs->lane_regs = &lane_regs_sc8280xp[0]; regs->lane_array_size = ARRAY_SIZE(lane_regs_sc8280xp); break; + case CAMSS_X1E80100: + regs->lane_regs = &lane_regs_x1e80100[0]; + regs->lane_array_size = ARRAY_SIZE(lane_regs_x1e80100); + regs->offset = 0x1000; + break; case CAMSS_8550: regs->lane_regs = &lane_regs_sm8550[0]; regs->lane_array_size = ARRAY_SIZE(lane_regs_sm8550); diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index c053616558a7..c622efcc92ff 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -586,7 +586,7 @@ int msm_csiphy_subdev_init(struct camss *camss, { struct device *dev = camss->dev; struct platform_device *pdev = to_platform_device(dev); - int i, j, k; + int i, j; int ret; csiphy->camss = camss; @@ -680,23 +680,21 @@ int msm_csiphy_subdev_init(struct camss *camss, for (j = 0; j < clock->nfreqs; j++) clock->freq[j] = res->clock_rate[i][j]; - for (k = 0; k < camss->res->csiphy_num; k++) { - csiphy->rate_set[i] = csiphy_match_clock_name(clock->name, - "csiphy%d_timer", k); - if (csiphy->rate_set[i]) - break; - - if (camss->res->version == CAMSS_660) { - csiphy->rate_set[i] = csiphy_match_clock_name(clock->name, - "csi%d_phy", k); - if (csiphy->rate_set[i]) - break; - } + csiphy->rate_set[i] = csiphy_match_clock_name(clock->name, + "csiphy%d_timer", + csiphy->id); + if (csiphy->rate_set[i]) + continue; - csiphy->rate_set[i] = csiphy_match_clock_name(clock->name, "csiphy%d", k); + if (camss->res->version == CAMSS_660) { + csiphy->rate_set[i] = csiphy_match_clock_name(clock->name, + "csi%d_phy", + csiphy->id); if (csiphy->rate_set[i]) - break; + continue; } + + csiphy->rate_set[i] = csiphy_match_clock_name(clock->name, "csiphy%d", csiphy->id); } /* CSIPHY supplies */ diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.h b/drivers/media/platform/qcom/camss/camss-csiphy.h index 86b98b37838e..ab91273303b9 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.h +++ b/drivers/media/platform/qcom/camss/camss-csiphy.h @@ -81,6 +81,7 @@ struct csiphy_hw_ops { }; struct csiphy_subdev_resources { + u8 id; const struct csiphy_hw_ops *hw_ops; const struct csiphy_formats *formats; }; diff --git a/drivers/media/platform/qcom/camss/camss-vfe-680.c b/drivers/media/platform/qcom/camss/camss-vfe-680.c new file mode 100644 index 000000000000..99036e7c1e76 --- /dev/null +++ b/drivers/media/platform/qcom/camss/camss-vfe-680.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * camss-vfe-680.c + * + * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module v680 + * + * Copyright (C) 2025 Linaro Ltd. + */ + +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/iopoll.h> + +#include "camss.h" +#include "camss-vfe.h" + +#define VFE_TOP_IRQn_STATUS(vfe, n) ((vfe_is_lite(vfe) ? 0x1c : 0x44) + (n) * 4) +#define VFE_TOP_IRQn_MASK(vfe, n) ((vfe_is_lite(vfe) ? 0x24 : 0x34) + (n) * 4) +#define VFE_TOP_IRQn_CLEAR(vfe, n) ((vfe_is_lite(vfe) ? 0x2c : 0x3c) + (n) * 4) +#define VFE_IRQ1_SOF(vfe, n) ((vfe_is_lite(vfe) ? BIT(2) : BIT(8)) << ((n) * 2)) +#define VFE_IRQ1_EOF(vfe, n) ((vfe_is_lite(vfe) ? BIT(3) : BIT(9)) << ((n) * 2)) +#define VFE_TOP_IRQ_CMD(vfe) (vfe_is_lite(vfe) ? 0x38 : 0x30) +#define VFE_TOP_IRQ_CMD_GLOBAL_CLEAR BIT(0) +#define VFE_TOP_DIAG_CONFIG (vfe_is_lite(vfe) ? 0x40 : 0x50) + +#define VFE_TOP_DEBUG_11(vfe) (vfe_is_lite(vfe) ? 0x40 : 0xcc) +#define VFE_TOP_DEBUG_12(vfe) (vfe_is_lite(vfe) ? 0x40 : 0xd0) +#define VFE_TOP_DEBUG_13(vfe) (vfe_is_lite(vfe) ? 0x40 : 0xd4) + +#define VFE_BUS_IRQn_MASK(vfe, n) ((vfe_is_lite(vfe) ? 0x218 : 0xc18) + (n) * 4) +#define VFE_BUS_IRQn_CLEAR(vfe, n) ((vfe_is_lite(vfe) ? 0x220 : 0xc20) + (n) * 4) +#define VFE_BUS_IRQn_STATUS(vfe, n) ((vfe_is_lite(vfe) ? 0x228 : 0xc28) + (n) * 4) +#define VFE_BUS_IRQ_GLOBAL_CLEAR(vfe) (vfe_is_lite(vfe) ? 0x230 : 0xc30) +#define VFE_BUS_WR_VIOLATION_STATUS(vfe) (vfe_is_lite(vfe) ? 0x264 : 0xc64) +#define VFE_BUS_WR_OVERFLOW_STATUS(vfe) (vfe_is_lite(vfe) ? 0x268 : 0xc68) +#define VFE_BUS_WR_IMAGE_VIOLATION_STATUS(vfe) (vfe_is_lite(vfe) ? 0x270 : 0xc70) + +#define VFE_BUS_WRITE_CLIENT_CFG(vfe, c) ((vfe_is_lite(vfe) ? 0x400 : 0xe00) + (c) * 0x100) +#define VFE_BUS_WRITE_CLIENT_CFG_EN BIT(0) +#define VFE_BUS_IMAGE_ADDR(vfe, c) ((vfe_is_lite(vfe) ? 0x404 : 0xe04) + (c) * 0x100) +#define VFE_BUS_FRAME_INCR(vfe, c) ((vfe_is_lite(vfe) ? 0x408 : 0xe08) + (c) * 0x100) +#define VFE_BUS_IMAGE_CFG0(vfe, c) ((vfe_is_lite(vfe) ? 0x40c : 0xe0c) + (c) * 0x100) +#define VFE_BUS_IMAGE_CFG0_DATA(h, s) (((h) << 16) | ((s) >> 4)) +#define WM_IMAGE_CFG_0_DEFAULT_WIDTH (0xFFFF) + +#define VFE_BUS_IMAGE_CFG1(vfe, c) ((vfe_is_lite(vfe) ? 0x410 : 0xe10) + (c) * 0x100) +#define VFE_BUS_IMAGE_CFG2(vfe, c) ((vfe_is_lite(vfe) ? 0x414 : 0xe14) + (c) * 0x100) +#define VFE_BUS_PACKER_CFG(vfe, c) ((vfe_is_lite(vfe) ? 0x418 : 0xe18) + (c) * 0x100) +#define VFE_BUS_IRQ_SUBSAMPLE_PERIOD(vfe, c) ((vfe_is_lite(vfe) ? 0x430 : 0xe30) + (c) * 0x100) +#define VFE_BUS_IRQ_SUBSAMPLE_PATTERN(vfe, c) ((vfe_is_lite(vfe) ? 0x434 : 0xe34) + (c) * 0x100) +#define VFE_BUS_FRAMEDROP_PERIOD(vfe, c) ((vfe_is_lite(vfe) ? 0x438 : 0xe38) + (c) * 0x100) +#define VFE_BUS_FRAMEDROP_PATTERN(vfe, c) ((vfe_is_lite(vfe) ? 0x43c : 0xe3c) + (c) * 0x100) +#define VFE_BUS_MMU_PREFETCH_CFG(vfe, c) ((vfe_is_lite(vfe) ? 0x460 : 0xe60) + (c) * 0x100) +#define VFE_BUS_MMU_PREFETCH_CFG_EN BIT(0) +#define VFE_BUS_MMU_PREFETCH_MAX_OFFSET(vfe, c) ((vfe_is_lite(vfe) ? 0x464 : 0xe64) + (c) * 0x100) +#define VFE_BUS_ADDR_STATUS0(vfe, c) ((vfe_is_lite(vfe) ? 0x470 : 0xe70) + (c) * 0x100) + +/* + * TODO: differentiate the port id based on requested type of RDI, BHIST etc + * + * IFE write master IDs + * + * VIDEO_FULL_Y 0 + * VIDEO_FULL_C 1 + * VIDEO_DS_4:1 2 + * VIDEO_DS_16:1 3 + * DISPLAY_FULL_Y 4 + * DISPLAY_FULL_C 5 + * DISPLAY_DS_4:1 6 + * DISPLAY_DS_16:1 7 + * FD_Y 8 + * FD_C 9 + * PIXEL_RAW 10 + * STATS_BE0 11 + * STATS_BHIST0 12 + * STATS_TINTLESS_BG 13 + * STATS_AWB_BG 14 + * STATS_AWB_BFW 15 + * STATS_BAF 16 + * STATS_BHIST 17 + * STATS_RS 18 + * STATS_IHIST 19 + * SPARSE_PD 20 + * PDAF_V2.0_PD_DATA 21 + * PDAF_V2.0_SAD 22 + * LCR 23 + * RDI0 24 + * RDI1 25 + * RDI2 26 + * LTM_STATS 27 + * + * IFE Lite write master IDs + * + * RDI0 0 + * RDI1 1 + * RDI2 2 + * RDI3 3 + * GAMMA 4 + * BE 5 + */ + +/* TODO: assign an ENUM in resources and use the provided master + * id directly for RDI, STATS, AWB_BG, BHIST. + * This macro only works because RDI is all we support right now. + */ +#define RDI_WM(n) ((vfe_is_lite(vfe) ? 0 : 24) + (n)) + +static void vfe_global_reset(struct vfe_device *vfe) +{ + /* VFE680 has no global reset, simply report a completion */ + complete(&vfe->reset_complete); +} + +/* + * vfe_isr - VFE module interrupt handler + * @irq: Interrupt line + * @dev: VFE device + * + * Return IRQ_HANDLED on success + */ +static irqreturn_t vfe_isr(int irq, void *dev) +{ + return IRQ_HANDLED; +} + +/* + * vfe_halt - Trigger halt on VFE module and wait to complete + * @vfe: VFE device + * + * Return 0 on success or a negative error code otherwise + */ +static int vfe_halt(struct vfe_device *vfe) +{ + /* rely on vfe_disable_output() to stop the VFE */ + return 0; +} + +static void vfe_disable_irq(struct vfe_device *vfe) +{ + writel(0u, vfe->base + VFE_TOP_IRQn_MASK(vfe, 0)); + writel(0u, vfe->base + VFE_TOP_IRQn_MASK(vfe, 1)); + writel(0u, vfe->base + VFE_BUS_IRQn_MASK(vfe, 0)); + writel(0u, vfe->base + VFE_BUS_IRQn_MASK(vfe, 1)); +} + +static void vfe_wm_update(struct vfe_device *vfe, u8 rdi, u32 addr, + struct vfe_line *line) +{ + u8 wm = RDI_WM(rdi); + + writel(addr, vfe->base + VFE_BUS_IMAGE_ADDR(vfe, wm)); +} + +static void vfe_wm_start(struct vfe_device *vfe, u8 rdi, struct vfe_line *line) +{ + struct v4l2_pix_format_mplane *pix = + &line->video_out.active_fmt.fmt.pix_mp; + u32 stride = pix->plane_fmt[0].bytesperline; + u32 cfg; + u8 wm; + + cfg = VFE_BUS_IMAGE_CFG0_DATA(pix->height, stride); + wm = RDI_WM(rdi); + + writel(cfg, vfe->base + VFE_BUS_IMAGE_CFG0(vfe, wm)); + writel(0, vfe->base + VFE_BUS_IMAGE_CFG1(vfe, wm)); + writel(stride, vfe->base + VFE_BUS_IMAGE_CFG2(vfe, wm)); + writel(0, vfe->base + VFE_BUS_PACKER_CFG(vfe, wm)); + + /* Set total frame increment value */ + writel(pix->plane_fmt[0].bytesperline * pix->height, + vfe->base + VFE_BUS_FRAME_INCR(vfe, wm)); + + /* MMU */ + writel(VFE_BUS_MMU_PREFETCH_CFG_EN, vfe->base + VFE_BUS_MMU_PREFETCH_CFG(vfe, wm)); + writel(~0u, vfe->base + VFE_BUS_MMU_PREFETCH_MAX_OFFSET(vfe, wm)); + + /* no dropped frames, one irq per frame */ + writel(1, vfe->base + VFE_BUS_FRAMEDROP_PATTERN(vfe, wm)); + writel(0, vfe->base + VFE_BUS_FRAMEDROP_PERIOD(vfe, wm)); + writel(1, vfe->base + VFE_BUS_IRQ_SUBSAMPLE_PATTERN(vfe, wm)); + writel(0, vfe->base + VFE_BUS_IRQ_SUBSAMPLE_PERIOD(vfe, wm)); + + /* We don't process IRQs for VFE in RDI mode at the moment */ + vfe_disable_irq(vfe); + + /* Enable WM */ + writel(VFE_BUS_WRITE_CLIENT_CFG_EN, + vfe->base + VFE_BUS_WRITE_CLIENT_CFG(vfe, wm)); + + dev_dbg(vfe->camss->dev, "RDI%d WM:%d width %d height %d stride %d\n", + rdi, wm, pix->width, pix->height, stride); +} + +static void vfe_wm_stop(struct vfe_device *vfe, u8 rdi) +{ + u8 wm = RDI_WM(rdi); + + writel(0, vfe->base + VFE_BUS_WRITE_CLIENT_CFG(vfe, wm)); +} + +static const struct camss_video_ops vfe_video_ops_680 = { + .queue_buffer = vfe_queue_buffer_v2, + .flush_buffers = vfe_flush_buffers, +}; + +static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) +{ + vfe->video_ops = vfe_video_ops_680; +} + +static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id) +{ + int port_id = line_id; + + camss_reg_update(vfe->camss, vfe->id, port_id, false); +} + +static inline void vfe_reg_update_clear(struct vfe_device *vfe, + enum vfe_line_id line_id) +{ + int port_id = line_id; + + camss_reg_update(vfe->camss, vfe->id, port_id, true); +} + +const struct vfe_hw_ops vfe_ops_680 = { + .global_reset = vfe_global_reset, + .hw_version = vfe_hw_version, + .isr = vfe_isr, + .pm_domain_off = vfe_pm_domain_off, + .pm_domain_on = vfe_pm_domain_on, + .subdev_init = vfe_subdev_init, + .vfe_disable = vfe_disable, + .vfe_enable = vfe_enable_v2, + .vfe_halt = vfe_halt, + .vfe_wm_start = vfe_wm_start, + .vfe_wm_stop = vfe_wm_stop, + .vfe_buf_done = vfe_buf_done, + .vfe_wm_update = vfe_wm_update, + .reg_update = vfe_reg_update, + .reg_update_clear = vfe_reg_update_clear, +}; diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index cf0e8f5c004a..4bca6c3abaff 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -346,6 +346,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, case CAMSS_8280XP: case CAMSS_845: case CAMSS_8550: + case CAMSS_X1E80100: switch (sink_code) { case MEDIA_BUS_FMT_YUYV8_1X16: { @@ -428,8 +429,8 @@ u32 vfe_hw_version(struct vfe_device *vfe) u32 rev = (hw_version >> HW_VERSION_REVISION) & 0xFFF; u32 step = (hw_version >> HW_VERSION_STEPPING) & 0xFFFF; - dev_info(vfe->camss->dev, "VFE:%d HW Version = %u.%u.%u\n", - vfe->id, gen, rev, step); + dev_dbg(vfe->camss->dev, "VFE:%d HW Version = %u.%u.%u\n", + vfe->id, gen, rev, step); return hw_version; } @@ -1973,6 +1974,7 @@ static int vfe_bpl_align(struct vfe_device *vfe) case CAMSS_8280XP: case CAMSS_845: case CAMSS_8550: + case CAMSS_X1E80100: ret = 16; break; default: diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index 9dec5bc0d1b1..a23f666be753 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -243,6 +243,7 @@ extern const struct vfe_hw_ops vfe_ops_4_7; extern const struct vfe_hw_ops vfe_ops_4_8; extern const struct vfe_hw_ops vfe_ops_170; extern const struct vfe_hw_ops vfe_ops_480; +extern const struct vfe_hw_ops vfe_ops_680; extern const struct vfe_hw_ops vfe_ops_780; int vfe_get(struct vfe_device *vfe); diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 6791dfea91b1..06f42875702f 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -46,6 +46,7 @@ static const struct camss_subdev_resources csiphy_res_8x16[] = { .reg = { "csiphy0", "csiphy0_clk_mux" }, .interrupt = { "csiphy0" }, .csiphy = { + .id = 0, .hw_ops = &csiphy_ops_2ph_1_0, .formats = &csiphy_formats_8x16 } @@ -62,6 +63,7 @@ static const struct camss_subdev_resources csiphy_res_8x16[] = { .reg = { "csiphy1", "csiphy1_clk_mux" }, .interrupt = { "csiphy1" }, .csiphy = { + .id = 1, .hw_ops = &csiphy_ops_2ph_1_0, .formats = &csiphy_formats_8x16 } @@ -318,6 +320,7 @@ static const struct camss_subdev_resources csiphy_res_8x96[] = { .reg = { "csiphy0", "csiphy0_clk_mux" }, .interrupt = { "csiphy0" }, .csiphy = { + .id = 0, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_8x96 } @@ -334,6 +337,7 @@ static const struct camss_subdev_resources csiphy_res_8x96[] = { .reg = { "csiphy1", "csiphy1_clk_mux" }, .interrupt = { "csiphy1" }, .csiphy = { + .id = 1, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_8x96 } @@ -350,6 +354,7 @@ static const struct camss_subdev_resources csiphy_res_8x96[] = { .reg = { "csiphy2", "csiphy2_clk_mux" }, .interrupt = { "csiphy2" }, .csiphy = { + .id = 2, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_8x96 } @@ -524,6 +529,7 @@ static const struct camss_subdev_resources csiphy_res_660[] = { .reg = { "csiphy0", "csiphy0_clk_mux" }, .interrupt = { "csiphy0" }, .csiphy = { + .id = 0, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_8x96 } @@ -542,6 +548,7 @@ static const struct camss_subdev_resources csiphy_res_660[] = { .reg = { "csiphy1", "csiphy1_clk_mux" }, .interrupt = { "csiphy1" }, .csiphy = { + .id = 1, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_8x96 } @@ -560,6 +567,7 @@ static const struct camss_subdev_resources csiphy_res_660[] = { .reg = { "csiphy2", "csiphy2_clk_mux" }, .interrupt = { "csiphy2" }, .csiphy = { + .id = 2, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_8x96 } @@ -751,6 +759,7 @@ static const struct camss_subdev_resources csiphy_res_670[] = { .reg = { "csiphy0" }, .interrupt = { "csiphy0" }, .csiphy = { + .id = 0, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -768,6 +777,7 @@ static const struct camss_subdev_resources csiphy_res_670[] = { .reg = { "csiphy1" }, .interrupt = { "csiphy1" }, .csiphy = { + .id = 1, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -785,6 +795,7 @@ static const struct camss_subdev_resources csiphy_res_670[] = { .reg = { "csiphy2" }, .interrupt = { "csiphy2" }, .csiphy = { + .id = 2, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -935,6 +946,7 @@ static const struct camss_subdev_resources csiphy_res_845[] = { .reg = { "csiphy0" }, .interrupt = { "csiphy0" }, .csiphy = { + .id = 0, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -957,6 +969,7 @@ static const struct camss_subdev_resources csiphy_res_845[] = { .reg = { "csiphy1" }, .interrupt = { "csiphy1" }, .csiphy = { + .id = 1, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -979,6 +992,7 @@ static const struct camss_subdev_resources csiphy_res_845[] = { .reg = { "csiphy2" }, .interrupt = { "csiphy2" }, .csiphy = { + .id = 2, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -1001,6 +1015,7 @@ static const struct camss_subdev_resources csiphy_res_845[] = { .reg = { "csiphy3" }, .interrupt = { "csiphy3" }, .csiphy = { + .id = 3, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -1179,6 +1194,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { .reg = { "csiphy0" }, .interrupt = { "csiphy0" }, .csiphy = { + .id = 0, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -1192,6 +1208,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { .reg = { "csiphy1" }, .interrupt = { "csiphy1" }, .csiphy = { + .id = 1, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -1205,6 +1222,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { .reg = { "csiphy2" }, .interrupt = { "csiphy2" }, .csiphy = { + .id = 2, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -1218,6 +1236,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { .reg = { "csiphy3" }, .interrupt = { "csiphy3" }, .csiphy = { + .id = 3, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -1231,6 +1250,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { .reg = { "csiphy4" }, .interrupt = { "csiphy4" }, .csiphy = { + .id = 4, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -1244,6 +1264,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { .reg = { "csiphy5" }, .interrupt = { "csiphy5" }, .csiphy = { + .id = 5, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -1458,6 +1479,7 @@ static const struct camss_subdev_resources csiphy_res_7280[] = { .reg = { "csiphy0" }, .interrupt = { "csiphy0" }, .csiphy = { + .id = 0, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sc7280 } @@ -1472,6 +1494,7 @@ static const struct camss_subdev_resources csiphy_res_7280[] = { .reg = { "csiphy1" }, .interrupt = { "csiphy1" }, .csiphy = { + .id = 1, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sc7280 } @@ -1486,6 +1509,7 @@ static const struct camss_subdev_resources csiphy_res_7280[] = { .reg = { "csiphy2" }, .interrupt = { "csiphy2" }, .csiphy = { + .id = 2, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sc7280 } @@ -1500,6 +1524,7 @@ static const struct camss_subdev_resources csiphy_res_7280[] = { .reg = { "csiphy3" }, .interrupt = { "csiphy3" }, .csiphy = { + .id = 3, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sc7280 } @@ -1514,6 +1539,7 @@ static const struct camss_subdev_resources csiphy_res_7280[] = { .reg = { "csiphy4" }, .interrupt = { "csiphy4" }, .csiphy = { + .id = 4, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sc7280 } @@ -1766,6 +1792,7 @@ static const struct camss_subdev_resources csiphy_res_sc8280xp[] = { .reg = { "csiphy0" }, .interrupt = { "csiphy0" }, .csiphy = { + .id = 0, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -1779,6 +1806,7 @@ static const struct camss_subdev_resources csiphy_res_sc8280xp[] = { .reg = { "csiphy1" }, .interrupt = { "csiphy1" }, .csiphy = { + .id = 1, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -1792,6 +1820,7 @@ static const struct camss_subdev_resources csiphy_res_sc8280xp[] = { .reg = { "csiphy2" }, .interrupt = { "csiphy2" }, .csiphy = { + .id = 2, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -1805,6 +1834,7 @@ static const struct camss_subdev_resources csiphy_res_sc8280xp[] = { .reg = { "csiphy3" }, .interrupt = { "csiphy3" }, .csiphy = { + .id = 3, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -2134,6 +2164,7 @@ static const struct camss_subdev_resources csiphy_res_8550[] = { .reg = { "csiphy0" }, .interrupt = { "csiphy0" }, .csiphy = { + .id = 0, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -2147,6 +2178,7 @@ static const struct camss_subdev_resources csiphy_res_8550[] = { .reg = { "csiphy1" }, .interrupt = { "csiphy1" }, .csiphy = { + .id = 1, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -2160,6 +2192,7 @@ static const struct camss_subdev_resources csiphy_res_8550[] = { .reg = { "csiphy2" }, .interrupt = { "csiphy2" }, .csiphy = { + .id = 2, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -2173,6 +2206,7 @@ static const struct camss_subdev_resources csiphy_res_8550[] = { .reg = { "csiphy3" }, .interrupt = { "csiphy3" }, .csiphy = { + .id = 3, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -2186,6 +2220,7 @@ static const struct camss_subdev_resources csiphy_res_8550[] = { .reg = { "csiphy4" }, .interrupt = { "csiphy4" }, .csiphy = { + .id = 4, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -2199,6 +2234,7 @@ static const struct camss_subdev_resources csiphy_res_8550[] = { .reg = { "csiphy5" }, .interrupt = { "csiphy5" }, .csiphy = { + .id = 5, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -2212,6 +2248,7 @@ static const struct camss_subdev_resources csiphy_res_8550[] = { .reg = { "csiphy6" }, .interrupt = { "csiphy6" }, .csiphy = { + .id = 6, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -2225,6 +2262,7 @@ static const struct camss_subdev_resources csiphy_res_8550[] = { .reg = { "csiphy7" }, .interrupt = { "csiphy7" }, .csiphy = { + .id = 7, .hw_ops = &csiphy_ops_3ph_1_0, .formats = &csiphy_formats_sdm845 } @@ -2445,6 +2483,299 @@ static const struct resources_icc icc_res_sm8550[] = { }, }; +static const struct camss_subdev_resources csiphy_res_x1e80100[] = { + /* CSIPHY0 */ + { + .regulators = { "vdd-csiphy-0p8-supply", + "vdd-csiphy-1p2-supply" }, + .clock = { "csiphy0", "csiphy0_timer" }, + .clock_rate = { { 300000000, 400000000, 480000000 }, + { 266666667, 400000000 } }, + .reg = { "csiphy0" }, + .interrupt = { "csiphy0" }, + .csiphy = { + .id = 0, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845 + }, + }, + /* CSIPHY1 */ + { + .regulators = { "vdd-csiphy-0p8-supply", + "vdd-csiphy-1p2-supply" }, + .clock = { "csiphy1", "csiphy1_timer" }, + .clock_rate = { { 300000000, 400000000, 480000000 }, + { 266666667, 400000000 } }, + .reg = { "csiphy1" }, + .interrupt = { "csiphy1" }, + .csiphy = { + .id = 1, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845 + }, + }, + /* CSIPHY2 */ + { + .regulators = { "vdd-csiphy-0p8-supply", + "vdd-csiphy-1p2-supply" }, + .clock = { "csiphy2", "csiphy2_timer" }, + .clock_rate = { { 300000000, 400000000, 480000000 }, + { 266666667, 400000000 } }, + .reg = { "csiphy2" }, + .interrupt = { "csiphy2" }, + .csiphy = { + .id = 2, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845 + }, + }, + /* CSIPHY4 */ + { + .regulators = { "vdd-csiphy-0p8-supply", + "vdd-csiphy-1p2-supply" }, + .clock = { "csiphy4", "csiphy4_timer" }, + .clock_rate = { { 300000000, 400000000, 480000000 }, + { 266666667, 400000000 } }, + .reg = { "csiphy4" }, + .interrupt = { "csiphy4" }, + .csiphy = { + .id = 4, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845 + }, + }, +}; + +static const struct camss_subdev_resources csid_res_x1e80100[] = { + /* CSID0 */ + { + .regulators = {}, + .clock = { "gcc_axi_hf", "gcc_axi_sf", "cpas_ahb", + "cpas_fast_ahb", "csid", "csid_csiphy_rx" }, + .clock_rate = { { 0 }, + { 0 }, + { 64000000, 80000000 }, + { 80000000, 100000000, 200000000, + 300000000, 400000000 }, + { 300000000, 400000000, 480000000 }, + { 300000000, 400000000, 480000000 }, }, + .reg = { "csid0" }, + .interrupt = { "csid0" }, + .csid = { + .hw_ops = &csid_ops_680, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_gen2 + }, + }, + /* CSID1 */ + { + .regulators = {}, + .clock = { "gcc_axi_hf", "gcc_axi_sf", "cpas_ahb", + "cpas_fast_ahb", "csid", "csid_csiphy_rx" }, + .clock_rate = { { 0 }, + { 0 }, + { 64000000, 80000000 }, + { 80000000, 100000000, 200000000, + 300000000, 400000000 }, + { 300000000, 400000000, 480000000 }, + { 300000000, 400000000, 480000000 }, }, + .reg = { "csid1" }, + .interrupt = { "csid1" }, + .csid = { + .hw_ops = &csid_ops_680, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_gen2 + }, + }, + /* CSID2 */ + { + .regulators = {}, + .clock = { "gcc_axi_hf", "gcc_axi_sf", "cpas_ahb", + "cpas_fast_ahb", "csid", "csid_csiphy_rx" }, + .clock_rate = { { 0 }, + { 0 }, + { 64000000, 80000000 }, + { 80000000, 100000000, 200000000, + 300000000, 400000000 }, + { 300000000, 400000000, 480000000 }, + { 300000000, 400000000, 480000000 }, }, + .reg = { "csid2" }, + .interrupt = { "csid2" }, + .csid = { + .hw_ops = &csid_ops_680, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_gen2 + }, + }, + /* CSID_LITE0 */ + { + .regulators = {}, + .clock = { "gcc_axi_hf", "gcc_axi_sf", "cpas_ahb", + "cpas_fast_ahb", "csid", "csid_csiphy_rx" }, + .clock_rate = { { 0 }, + { 0 }, + { 64000000, 80000000 }, + { 80000000, 100000000, 200000000, + 300000000, 400000000 }, + { 300000000, 400000000, 480000000 }, + { 300000000, 400000000, 480000000 }, }, + .reg = { "csid_lite0" }, + .interrupt = { "csid_lite0" }, + .csid = { + .is_lite = true, + .hw_ops = &csid_ops_680, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_gen2 + } + }, + /* CSID_LITE1 */ + { + .regulators = {}, + .clock = { "gcc_axi_hf", "gcc_axi_sf", "cpas_ahb", + "cpas_fast_ahb", "csid", "csid_csiphy_rx" }, + .clock_rate = { { 0 }, + { 0 }, + { 64000000, 80000000 }, + { 80000000, 100000000, 200000000, + 300000000, 400000000 }, + { 300000000, 400000000, 480000000 }, + { 300000000, 400000000, 480000000 }, }, + + .reg = { "csid_lite1" }, + .interrupt = { "csid_lite1" }, + .csid = { + .is_lite = true, + .hw_ops = &csid_ops_680, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_gen2 + } + }, +}; + +static const struct camss_subdev_resources vfe_res_x1e80100[] = { + /* IFE0 */ + { + .regulators = {}, + .clock = {"camnoc_rt_axi", "camnoc_nrt_axi", "cpas_ahb", + "cpas_fast_ahb", "cpas_vfe0", "vfe0_fast_ahb", + "vfe0" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 345600000, 432000000, 594000000, 675000000, + 727000000 }, }, + .reg = { "vfe0" }, + .interrupt = { "vfe0" }, + .vfe = { + .line_num = 4, + .pd_name = "ife0", + .hw_ops = &vfe_ops_680, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + }, + }, + /* IFE1 */ + { + .regulators = {}, + .clock = { "camnoc_rt_axi", "camnoc_nrt_axi", "cpas_ahb", + "cpas_fast_ahb", "cpas_vfe1", "vfe1_fast_ahb", + "vfe1" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 345600000, 432000000, 594000000, 675000000, + 727000000 }, }, + .reg = { "vfe1" }, + .interrupt = { "vfe1" }, + .vfe = { + .line_num = 4, + .pd_name = "ife1", + .hw_ops = &vfe_ops_680, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + }, + }, + /* IFE_LITE_0 */ + { + .regulators = {}, + .clock = { "camnoc_rt_axi", "camnoc_nrt_axi", "cpas_ahb", + "vfe_lite_ahb", "cpas_vfe_lite", "vfe_lite", + "vfe_lite_csid" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 266666667, 400000000, 480000000 }, + { 266666667, 400000000, 480000000 }, }, + .reg = { "vfe_lite0" }, + .interrupt = { "vfe_lite0" }, + .vfe = { + .is_lite = true, + .line_num = 4, + .hw_ops = &vfe_ops_680, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + }, + }, + /* IFE_LITE_1 */ + { + .regulators = {}, + .clock = { "camnoc_rt_axi", "camnoc_nrt_axi", "cpas_ahb", + "vfe_lite_ahb", "cpas_vfe_lite", "vfe_lite", + "vfe_lite_csid" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 266666667, 400000000, 480000000 }, + { 266666667, 400000000, 480000000 }, }, + .reg = { "vfe_lite1" }, + .interrupt = { "vfe_lite1" }, + .vfe = { + .is_lite = true, + .line_num = 4, + .hw_ops = &vfe_ops_680, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + }, + }, +}; + +static const struct resources_icc icc_res_x1e80100[] = { + { + .name = "ahb", + .icc_bw_tbl.avg = 150000, + .icc_bw_tbl.peak = 300000, + }, + { + .name = "hf_mnoc", + .icc_bw_tbl.avg = 2097152, + .icc_bw_tbl.peak = 2097152, + }, + { + .name = "sf_mnoc", + .icc_bw_tbl.avg = 2097152, + .icc_bw_tbl.peak = 2097152, + }, + { + .name = "sf_icp_mnoc", + .icc_bw_tbl.avg = 2097152, + .icc_bw_tbl.peak = 2097152, + }, +}; + +static const struct resources_wrapper csid_wrapper_res_x1e80100 = { + .reg = "csid_wrapper", +}; + /* * camss_add_clock_margin - Add margin to clock frequency rate * @rate: Clock frequency rate @@ -2663,6 +2994,15 @@ static int camss_of_parse_endpoint_node(struct device *dev, if (ret) return ret; + /* + * Most SoCs support both D-PHY and C-PHY standards, but currently only + * D-PHY is supported in the driver. + */ + if (vep.bus_type != V4L2_MBUS_CSI2_DPHY) { + dev_err(dev, "Unsupported bus type %d\n", vep.bus_type); + return -EINVAL; + } + csd->interface.csiphy_id = vep.base.port; mipi_csi2 = &vep.bus.mipi_csi2; @@ -2749,7 +3089,8 @@ static int camss_init_subdevices(struct camss *camss) for (i = 0; i < camss->res->csiphy_num; i++) { ret = msm_csiphy_subdev_init(camss, &camss->csiphy[i], - &res->csiphy_res[i], i); + &res->csiphy_res[i], + res->csiphy_res[i].csiphy.id); if (ret < 0) { dev_err(camss->dev, "Failed to init csiphy%d sub-device: %d\n", @@ -3505,6 +3846,21 @@ static const struct camss_resources sm8550_resources = { .link_entities = camss_link_entities }; +static const struct camss_resources x1e80100_resources = { + .version = CAMSS_X1E80100, + .pd_name = "top", + .csiphy_res = csiphy_res_x1e80100, + .csid_res = csid_res_x1e80100, + .vfe_res = vfe_res_x1e80100, + .csid_wrapper_res = &csid_wrapper_res_x1e80100, + .icc_res = icc_res_x1e80100, + .icc_path_num = ARRAY_SIZE(icc_res_x1e80100), + .csiphy_num = ARRAY_SIZE(csiphy_res_x1e80100), + .csid_num = ARRAY_SIZE(csid_res_x1e80100), + .vfe_num = ARRAY_SIZE(vfe_res_x1e80100), + .link_entities = camss_link_entities +}; + static const struct of_device_id camss_dt_match[] = { { .compatible = "qcom,msm8916-camss", .data = &msm8916_resources }, { .compatible = "qcom,msm8953-camss", .data = &msm8953_resources }, @@ -3516,6 +3872,7 @@ static const struct of_device_id camss_dt_match[] = { { .compatible = "qcom,sdm845-camss", .data = &sdm845_resources }, { .compatible = "qcom,sm8250-camss", .data = &sm8250_resources }, { .compatible = "qcom,sm8550-camss", .data = &sm8550_resources }, + { .compatible = "qcom,x1e80100-camss", .data = &x1e80100_resources }, { } }; diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index b284b910ce42..63c0afee154a 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -86,6 +86,7 @@ enum camss_version { CAMSS_8280XP, CAMSS_845, CAMSS_8550, + CAMSS_X1E80100, }; enum icc_count { diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/platform/qcom/iris/Makefile index 35390534534e..e86d00ee6f15 100644 --- a/drivers/media/platform/qcom/iris/Makefile +++ b/drivers/media/platform/qcom/iris/Makefile @@ -10,7 +10,7 @@ qcom-iris-objs += \ iris_hfi_gen2_packet.o \ iris_hfi_gen2_response.o \ iris_hfi_queue.o \ - iris_platform_sm8550.o \ + iris_platform_gen2.o \ iris_power.o \ iris_probe.o \ iris_resources.o \ @@ -20,7 +20,7 @@ qcom-iris-objs += \ iris_vb2.o \ iris_vdec.o \ iris_vpu2.o \ - iris_vpu3.o \ + iris_vpu3x.o \ iris_vpu_buffer.o \ iris_vpu_common.o \ diff --git a/drivers/media/platform/qcom/iris/iris_core.h b/drivers/media/platform/qcom/iris/iris_core.h index 37fb4919fecc..aeeac32a1f6d 100644 --- a/drivers/media/platform/qcom/iris/iris_core.h +++ b/drivers/media/platform/qcom/iris/iris_core.h @@ -43,6 +43,7 @@ struct icc_info { * @clock_tbl: table of iris clocks * @clk_count: count of iris clocks * @resets: table of iris reset clocks + * @controller_resets: table of controller reset clocks * @iris_platform_data: a structure for platform data * @state: current state of core * @iface_q_table_daddr: device address for interface queue table memory @@ -82,6 +83,7 @@ struct iris_core { struct clk_bulk_data *clock_tbl; u32 clk_count; struct reset_control_bulk_data *resets; + struct reset_control_bulk_data *controller_resets; const struct iris_platform_data *iris_platform_data; enum iris_core_state state; dma_addr_t iface_q_table_daddr; diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c index 7c493b4a75db..f1b5cd56db32 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -53,8 +53,10 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) } mem_virt = memremap(mem_phys, res_size, MEMREMAP_WC); - if (!mem_virt) + if (!mem_virt) { + ret = -ENOMEM; goto err_release_fw; + } ret = qcom_mdt_load(dev, firmware, fw_name, pas_id, mem_virt, mem_phys, res_size, NULL); diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h index f6b15d2805fb..ac76d9e1ef9c 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_common.h +++ b/drivers/media/platform/qcom/iris/iris_platform_common.h @@ -33,8 +33,10 @@ enum pipe_type { PIPE_4 = 4, }; +extern struct iris_platform_data qcs8300_data; extern struct iris_platform_data sm8250_data; extern struct iris_platform_data sm8550_data; +extern struct iris_platform_data sm8650_data; enum platform_clk_type { IRIS_AXI_CLK, @@ -156,6 +158,8 @@ struct iris_platform_data { unsigned int clk_tbl_size; const char * const *clk_rst_tbl; unsigned int clk_rst_tbl_size; + const char * const *controller_rst_tbl; + unsigned int controller_rst_tbl_size; u64 dma_mask; const char *fwname; u32 pas_id; diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8550.c b/drivers/media/platform/qcom/iris/iris_platform_gen2.c index 35d278996c43..1e69ba15db0f 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_sm8550.c +++ b/drivers/media/platform/qcom/iris/iris_platform_gen2.c @@ -10,6 +10,9 @@ #include "iris_platform_common.h" #include "iris_vpu_common.h" +#include "iris_platform_qcs8300.h" +#include "iris_platform_sm8650.h" + #define VIDEO_ARCH_LX 1 static struct platform_inst_fw_cap inst_fw_cap_sm8550[] = { @@ -264,3 +267,119 @@ struct iris_platform_data sm8550_data = { .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl, .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl), }; + +/* + * Shares most of SM8550 data except: + * - vpu_ops to iris_vpu33_ops + * - clk_rst_tbl to sm8650_clk_reset_table + * - controller_rst_tbl to sm8650_controller_reset_table + * - fwname to "qcom/vpu/vpu33_p4.mbn" + */ +struct iris_platform_data sm8650_data = { + .get_instance = iris_hfi_gen2_get_instance, + .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, + .init_hfi_response_ops = iris_hfi_gen2_response_ops_init, + .vpu_ops = &iris_vpu33_ops, + .set_preset_registers = iris_set_sm8550_preset_registers, + .icc_tbl = sm8550_icc_table, + .icc_tbl_size = ARRAY_SIZE(sm8550_icc_table), + .clk_rst_tbl = sm8650_clk_reset_table, + .clk_rst_tbl_size = ARRAY_SIZE(sm8650_clk_reset_table), + .controller_rst_tbl = sm8650_controller_reset_table, + .controller_rst_tbl_size = ARRAY_SIZE(sm8650_controller_reset_table), + .bw_tbl_dec = sm8550_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(sm8550_bw_table_dec), + .pmdomain_tbl = sm8550_pmdomain_table, + .pmdomain_tbl_size = ARRAY_SIZE(sm8550_pmdomain_table), + .opp_pd_tbl = sm8550_opp_pd_table, + .opp_pd_tbl_size = ARRAY_SIZE(sm8550_opp_pd_table), + .clk_tbl = sm8550_clk_table, + .clk_tbl_size = ARRAY_SIZE(sm8550_clk_table), + /* Upper bound of DMA address range */ + .dma_mask = 0xe0000000 - 1, + .fwname = "qcom/vpu/vpu33_p4.mbn", + .pas_id = IRIS_PAS_ID, + .inst_caps = &platform_inst_cap_sm8550, + .inst_fw_caps = inst_fw_cap_sm8550, + .inst_fw_caps_size = ARRAY_SIZE(inst_fw_cap_sm8550), + .tz_cp_config_data = &tz_cp_config_sm8550, + .core_arch = VIDEO_ARCH_LX, + .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, + .ubwc_config = &ubwc_config_sm8550, + .num_vpp_pipe = 4, + .max_session_count = 16, + .max_core_mbpf = ((8192 * 4352) / 256) * 2, + .input_config_params = + sm8550_vdec_input_config_params, + .input_config_params_size = + ARRAY_SIZE(sm8550_vdec_input_config_params), + .output_config_params = + sm8550_vdec_output_config_params, + .output_config_params_size = + ARRAY_SIZE(sm8550_vdec_output_config_params), + .dec_input_prop = sm8550_vdec_subscribe_input_properties, + .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), + .dec_output_prop = sm8550_vdec_subscribe_output_properties, + .dec_output_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_output_properties), + + .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, + .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), + .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl, + .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl), +}; + +/* + * Shares most of SM8550 data except: + * - inst_caps to platform_inst_cap_qcs8300 + * - inst_fw_caps to inst_fw_cap_qcs8300 + */ +struct iris_platform_data qcs8300_data = { + .get_instance = iris_hfi_gen2_get_instance, + .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, + .init_hfi_response_ops = iris_hfi_gen2_response_ops_init, + .vpu_ops = &iris_vpu3_ops, + .set_preset_registers = iris_set_sm8550_preset_registers, + .icc_tbl = sm8550_icc_table, + .icc_tbl_size = ARRAY_SIZE(sm8550_icc_table), + .clk_rst_tbl = sm8550_clk_reset_table, + .clk_rst_tbl_size = ARRAY_SIZE(sm8550_clk_reset_table), + .bw_tbl_dec = sm8550_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(sm8550_bw_table_dec), + .pmdomain_tbl = sm8550_pmdomain_table, + .pmdomain_tbl_size = ARRAY_SIZE(sm8550_pmdomain_table), + .opp_pd_tbl = sm8550_opp_pd_table, + .opp_pd_tbl_size = ARRAY_SIZE(sm8550_opp_pd_table), + .clk_tbl = sm8550_clk_table, + .clk_tbl_size = ARRAY_SIZE(sm8550_clk_table), + /* Upper bound of DMA address range */ + .dma_mask = 0xe0000000 - 1, + .fwname = "qcom/vpu/vpu30_p4_s6.mbn", + .pas_id = IRIS_PAS_ID, + .inst_caps = &platform_inst_cap_qcs8300, + .inst_fw_caps = inst_fw_cap_qcs8300, + .inst_fw_caps_size = ARRAY_SIZE(inst_fw_cap_qcs8300), + .tz_cp_config_data = &tz_cp_config_sm8550, + .core_arch = VIDEO_ARCH_LX, + .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, + .ubwc_config = &ubwc_config_sm8550, + .num_vpp_pipe = 2, + .max_session_count = 16, + .max_core_mbpf = ((4096 * 2176) / 256) * 4, + .input_config_params = + sm8550_vdec_input_config_params, + .input_config_params_size = + ARRAY_SIZE(sm8550_vdec_input_config_params), + .output_config_params = + sm8550_vdec_output_config_params, + .output_config_params_size = + ARRAY_SIZE(sm8550_vdec_output_config_params), + .dec_input_prop = sm8550_vdec_subscribe_input_properties, + .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), + .dec_output_prop = sm8550_vdec_subscribe_output_properties, + .dec_output_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_output_properties), + + .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, + .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), + .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl, + .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl), +}; diff --git a/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h b/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h new file mode 100644 index 000000000000..f82355d72fcf --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h @@ -0,0 +1,124 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +static struct platform_inst_fw_cap inst_fw_cap_qcs8300[] = { + { + .cap_id = PROFILE, + .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), + .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = LEVEL, + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2), + .value = V4L2_MPEG_VIDEO_H264_LEVEL_6_1, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = INPUT_BUF_HOST_MAX_COUNT, + .min = DEFAULT_MAX_HOST_BUF_COUNT, + .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT, + .step_or_mask = 1, + .value = DEFAULT_MAX_HOST_BUF_COUNT, + .hfi_id = HFI_PROP_BUFFER_HOST_MAX_COUNT, + .flags = CAP_FLAG_INPUT_PORT, + .set = iris_set_u32, + }, + { + .cap_id = STAGE, + .min = STAGE_1, + .max = STAGE_2, + .step_or_mask = 1, + .value = STAGE_2, + .hfi_id = HFI_PROP_STAGE, + .set = iris_set_stage, + }, + { + .cap_id = PIPE, + .min = PIPE_1, + .max = PIPE_2, + .step_or_mask = 1, + .value = PIPE_2, + .hfi_id = HFI_PROP_PIPE, + .set = iris_set_pipe, + }, + { + .cap_id = POC, + .min = 0, + .max = 2, + .step_or_mask = 1, + .value = 1, + .hfi_id = HFI_PROP_PIC_ORDER_CNT_TYPE, + }, + { + .cap_id = CODED_FRAMES, + .min = CODED_FRAMES_PROGRESSIVE, + .max = CODED_FRAMES_PROGRESSIVE, + .step_or_mask = 0, + .value = CODED_FRAMES_PROGRESSIVE, + .hfi_id = HFI_PROP_CODED_FRAMES, + }, + { + .cap_id = BIT_DEPTH, + .min = BIT_DEPTH_8, + .max = BIT_DEPTH_8, + .step_or_mask = 1, + .value = BIT_DEPTH_8, + .hfi_id = HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + }, + { + .cap_id = RAP_FRAME, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 1, + .hfi_id = HFI_PROP_DEC_START_FROM_RAP_FRAME, + .flags = CAP_FLAG_INPUT_PORT, + .set = iris_set_u32, + }, +}; + +static struct platform_inst_caps platform_inst_cap_qcs8300 = { + .min_frame_width = 96, + .max_frame_width = 4096, + .min_frame_height = 96, + .max_frame_height = 4096, + .max_mbpf = (4096 * 2176) / 256, + .mb_cycles_vpp = 200, + .mb_cycles_fw = 326389, + .mb_cycles_fw_vpp = 44156, + .num_comv = 0, +}; diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8650.h b/drivers/media/platform/qcom/iris/iris_platform_sm8650.h new file mode 100644 index 000000000000..75e9d572e788 --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_platform_sm8650.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __IRIS_PLATFORM_SM8650_H__ +#define __IRIS_PLATFORM_SM8650_H__ + +static const char * const sm8650_clk_reset_table[] = { "bus", "core" }; + +static const char * const sm8650_controller_reset_table[] = { "xo" }; + +#endif diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c index aca442dcc153..9a7ce142f700 100644 --- a/drivers/media/platform/qcom/iris/iris_probe.c +++ b/drivers/media/platform/qcom/iris/iris_probe.c @@ -91,25 +91,40 @@ static int iris_init_clocks(struct iris_core *core) return 0; } -static int iris_init_resets(struct iris_core *core) +static int iris_init_reset_table(struct iris_core *core, + struct reset_control_bulk_data **resets, + const char * const *rst_tbl, u32 rst_tbl_size) { - const char * const *rst_tbl; - u32 rst_tbl_size; u32 i = 0; - rst_tbl = core->iris_platform_data->clk_rst_tbl; - rst_tbl_size = core->iris_platform_data->clk_rst_tbl_size; - - core->resets = devm_kzalloc(core->dev, - sizeof(*core->resets) * rst_tbl_size, - GFP_KERNEL); - if (!core->resets) + *resets = devm_kzalloc(core->dev, + sizeof(struct reset_control_bulk_data) * rst_tbl_size, + GFP_KERNEL); + if (!*resets) return -ENOMEM; for (i = 0; i < rst_tbl_size; i++) - core->resets[i].id = rst_tbl[i]; + (*resets)[i].id = rst_tbl[i]; + + return devm_reset_control_bulk_get_exclusive(core->dev, rst_tbl_size, *resets); +} + +static int iris_init_resets(struct iris_core *core) +{ + int ret; + + ret = iris_init_reset_table(core, &core->resets, + core->iris_platform_data->clk_rst_tbl, + core->iris_platform_data->clk_rst_tbl_size); + if (ret) + return ret; - return devm_reset_control_bulk_get_exclusive(core->dev, rst_tbl_size, core->resets); + if (!core->iris_platform_data->controller_rst_tbl_size) + return 0; + + return iris_init_reset_table(core, &core->controller_resets, + core->iris_platform_data->controller_rst_tbl, + core->iris_platform_data->controller_rst_tbl_size); } static int iris_init_resources(struct iris_core *core) @@ -321,15 +336,23 @@ static const struct dev_pm_ops iris_pm_ops = { static const struct of_device_id iris_dt_match[] = { { - .compatible = "qcom,sm8550-iris", - .data = &sm8550_data, + .compatible = "qcom,qcs8300-iris", + .data = &qcs8300_data, }, #if (!IS_ENABLED(CONFIG_VIDEO_QCOM_VENUS)) - { - .compatible = "qcom,sm8250-venus", - .data = &sm8250_data, - }, + { + .compatible = "qcom,sm8250-venus", + .data = &sm8250_data, + }, #endif + { + .compatible = "qcom,sm8550-iris", + .data = &sm8550_data, + }, + { + .compatible = "qcom,sm8650-iris", + .data = &sm8650_data, + }, { }, }; MODULE_DEVICE_TABLE(of, iris_dt_match); diff --git a/drivers/media/platform/qcom/iris/iris_vpu2.c b/drivers/media/platform/qcom/iris/iris_vpu2.c index 8f502aed43ce..7cf1bfc352d3 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu2.c +++ b/drivers/media/platform/qcom/iris/iris_vpu2.c @@ -34,5 +34,6 @@ static u64 iris_vpu2_calc_freq(struct iris_inst *inst, size_t data_size) const struct vpu_ops iris_vpu2_ops = { .power_off_hw = iris_vpu_power_off_hw, + .power_off_controller = iris_vpu_power_off_controller, .calc_freq = iris_vpu2_calc_freq, }; diff --git a/drivers/media/platform/qcom/iris/iris_vpu3.c b/drivers/media/platform/qcom/iris/iris_vpu3.c deleted file mode 100644 index b484638e6105..000000000000 --- a/drivers/media/platform/qcom/iris/iris_vpu3.c +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. - */ - -#include <linux/iopoll.h> - -#include "iris_instance.h" -#include "iris_vpu_common.h" -#include "iris_vpu_register_defines.h" - -#define AON_MVP_NOC_RESET 0x0001F000 - -#define WRAPPER_CORE_CLOCK_CONFIG (WRAPPER_BASE_OFFS + 0x88) -#define CORE_CLK_RUN 0x0 - -#define CPU_CS_AHB_BRIDGE_SYNC_RESET (CPU_CS_BASE_OFFS + 0x160) -#define CORE_BRIDGE_SW_RESET BIT(0) -#define CORE_BRIDGE_HW_RESET_DISABLE BIT(1) - -#define AON_WRAPPER_MVP_NOC_RESET_REQ (AON_MVP_NOC_RESET + 0x000) -#define VIDEO_NOC_RESET_REQ (BIT(0) | BIT(1)) - -#define AON_WRAPPER_MVP_NOC_RESET_ACK (AON_MVP_NOC_RESET + 0x004) - -#define VCODEC_SS_IDLE_STATUSN (VCODEC_BASE_OFFS + 0x70) - -static bool iris_vpu3_hw_power_collapsed(struct iris_core *core) -{ - u32 value, pwr_status; - - value = readl(core->reg_base + WRAPPER_CORE_POWER_STATUS); - pwr_status = value & BIT(1); - - return pwr_status ? false : true; -} - -static void iris_vpu3_power_off_hardware(struct iris_core *core) -{ - u32 reg_val = 0, value, i; - int ret; - - if (iris_vpu3_hw_power_collapsed(core)) - goto disable_power; - - dev_err(core->dev, "video hw is power on\n"); - - value = readl(core->reg_base + WRAPPER_CORE_CLOCK_CONFIG); - if (value) - writel(CORE_CLK_RUN, core->reg_base + WRAPPER_CORE_CLOCK_CONFIG); - - for (i = 0; i < core->iris_platform_data->num_vpp_pipe; i++) { - ret = readl_poll_timeout(core->reg_base + VCODEC_SS_IDLE_STATUSN + 4 * i, - reg_val, reg_val & 0x400000, 2000, 20000); - if (ret) - goto disable_power; - } - - writel(VIDEO_NOC_RESET_REQ, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_REQ); - - ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_RESET_ACK, - reg_val, reg_val & 0x3, 200, 2000); - if (ret) - goto disable_power; - - writel(0x0, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_REQ); - - ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_RESET_ACK, - reg_val, !(reg_val & 0x3), 200, 2000); - if (ret) - goto disable_power; - - writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE, - core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); - writel(CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); - writel(0x0, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); - -disable_power: - iris_vpu_power_off_hw(core); -} - -static u64 iris_vpu3_calculate_frequency(struct iris_inst *inst, size_t data_size) -{ - struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps; - struct v4l2_format *inp_f = inst->fmt_src; - u32 height, width, mbs_per_second, mbpf; - u64 fw_cycles, fw_vpp_cycles; - u64 vsp_cycles, vpp_cycles; - u32 fps = DEFAULT_FPS; - - width = max(inp_f->fmt.pix_mp.width, inst->crop.width); - height = max(inp_f->fmt.pix_mp.height, inst->crop.height); - - mbpf = NUM_MBS_PER_FRAME(height, width); - mbs_per_second = mbpf * fps; - - fw_cycles = fps * caps->mb_cycles_fw; - fw_vpp_cycles = fps * caps->mb_cycles_fw_vpp; - - vpp_cycles = mult_frac(mbs_per_second, caps->mb_cycles_vpp, (u32)inst->fw_caps[PIPE].value); - /* 21 / 20 is minimum overhead factor */ - vpp_cycles += max(div_u64(vpp_cycles, 20), fw_vpp_cycles); - - /* 1.059 is multi-pipe overhead */ - if (inst->fw_caps[PIPE].value > 1) - vpp_cycles += div_u64(vpp_cycles * 59, 1000); - - vsp_cycles = fps * data_size * 8; - vsp_cycles = div_u64(vsp_cycles, 2); - /* VSP FW overhead 1.05 */ - vsp_cycles = div_u64(vsp_cycles * 21, 20); - - if (inst->fw_caps[STAGE].value == STAGE_1) - vsp_cycles = vsp_cycles * 3; - - return max3(vpp_cycles, vsp_cycles, fw_cycles); -} - -const struct vpu_ops iris_vpu3_ops = { - .power_off_hw = iris_vpu3_power_off_hardware, - .calc_freq = iris_vpu3_calculate_frequency, -}; diff --git a/drivers/media/platform/qcom/iris/iris_vpu3x.c b/drivers/media/platform/qcom/iris/iris_vpu3x.c new file mode 100644 index 000000000000..9b7c9a1495ee --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_vpu3x.c @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include <linux/iopoll.h> +#include <linux/reset.h> + +#include "iris_instance.h" +#include "iris_vpu_common.h" +#include "iris_vpu_register_defines.h" + +#define WRAPPER_TZ_BASE_OFFS 0x000C0000 +#define AON_BASE_OFFS 0x000E0000 +#define AON_MVP_NOC_RESET 0x0001F000 + +#define WRAPPER_DEBUG_BRIDGE_LPI_CONTROL (WRAPPER_BASE_OFFS + 0x54) +#define WRAPPER_DEBUG_BRIDGE_LPI_STATUS (WRAPPER_BASE_OFFS + 0x58) +#define WRAPPER_IRIS_CPU_NOC_LPI_CONTROL (WRAPPER_BASE_OFFS + 0x5C) +#define REQ_POWER_DOWN_PREP BIT(0) +#define WRAPPER_IRIS_CPU_NOC_LPI_STATUS (WRAPPER_BASE_OFFS + 0x60) +#define WRAPPER_CORE_CLOCK_CONFIG (WRAPPER_BASE_OFFS + 0x88) +#define CORE_CLK_RUN 0x0 + +#define WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG (WRAPPER_TZ_BASE_OFFS + 0x14) +#define CTL_AXI_CLK_HALT BIT(0) +#define CTL_CLK_HALT BIT(1) + +#define WRAPPER_TZ_QNS4PDXFIFO_RESET (WRAPPER_TZ_BASE_OFFS + 0x18) +#define RESET_HIGH BIT(0) + +#define CPU_CS_AHB_BRIDGE_SYNC_RESET (CPU_CS_BASE_OFFS + 0x160) +#define CORE_BRIDGE_SW_RESET BIT(0) +#define CORE_BRIDGE_HW_RESET_DISABLE BIT(1) + +#define CPU_CS_X2RPMH (CPU_CS_BASE_OFFS + 0x168) +#define MSK_SIGNAL_FROM_TENSILICA BIT(0) +#define MSK_CORE_POWER_ON BIT(1) + +#define AON_WRAPPER_MVP_NOC_RESET_REQ (AON_MVP_NOC_RESET + 0x000) +#define VIDEO_NOC_RESET_REQ (BIT(0) | BIT(1)) + +#define AON_WRAPPER_MVP_NOC_RESET_ACK (AON_MVP_NOC_RESET + 0x004) + +#define VCODEC_SS_IDLE_STATUSN (VCODEC_BASE_OFFS + 0x70) + +#define AON_WRAPPER_MVP_NOC_LPI_CONTROL (AON_BASE_OFFS) +#define AON_WRAPPER_MVP_NOC_LPI_STATUS (AON_BASE_OFFS + 0x4) + +#define AON_WRAPPER_MVP_NOC_CORE_SW_RESET (AON_BASE_OFFS + 0x18) +#define SW_RESET BIT(0) +#define AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL (AON_BASE_OFFS + 0x20) +#define NOC_HALT BIT(0) +#define AON_WRAPPER_SPARE (AON_BASE_OFFS + 0x28) + +static bool iris_vpu3x_hw_power_collapsed(struct iris_core *core) +{ + u32 value, pwr_status; + + value = readl(core->reg_base + WRAPPER_CORE_POWER_STATUS); + pwr_status = value & BIT(1); + + return pwr_status ? false : true; +} + +static void iris_vpu3_power_off_hardware(struct iris_core *core) +{ + u32 reg_val = 0, value, i; + int ret; + + if (iris_vpu3x_hw_power_collapsed(core)) + goto disable_power; + + dev_err(core->dev, "video hw is power on\n"); + + value = readl(core->reg_base + WRAPPER_CORE_CLOCK_CONFIG); + if (value) + writel(CORE_CLK_RUN, core->reg_base + WRAPPER_CORE_CLOCK_CONFIG); + + for (i = 0; i < core->iris_platform_data->num_vpp_pipe; i++) { + ret = readl_poll_timeout(core->reg_base + VCODEC_SS_IDLE_STATUSN + 4 * i, + reg_val, reg_val & 0x400000, 2000, 20000); + if (ret) + goto disable_power; + } + + writel(VIDEO_NOC_RESET_REQ, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_REQ); + + ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_RESET_ACK, + reg_val, reg_val & 0x3, 200, 2000); + if (ret) + goto disable_power; + + writel(0x0, core->reg_base + AON_WRAPPER_MVP_NOC_RESET_REQ); + + ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_RESET_ACK, + reg_val, !(reg_val & 0x3), 200, 2000); + if (ret) + goto disable_power; + + writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE, + core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); + writel(CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); + writel(0x0, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); + +disable_power: + iris_vpu_power_off_hw(core); +} + +static void iris_vpu33_power_off_hardware(struct iris_core *core) +{ + u32 reg_val = 0, value, i; + int ret; + + if (iris_vpu3x_hw_power_collapsed(core)) + goto disable_power; + + dev_err(core->dev, "video hw is power on\n"); + + value = readl(core->reg_base + WRAPPER_CORE_CLOCK_CONFIG); + if (value) + writel(CORE_CLK_RUN, core->reg_base + WRAPPER_CORE_CLOCK_CONFIG); + + for (i = 0; i < core->iris_platform_data->num_vpp_pipe; i++) { + ret = readl_poll_timeout(core->reg_base + VCODEC_SS_IDLE_STATUSN + 4 * i, + reg_val, reg_val & 0x400000, 2000, 20000); + if (ret) + goto disable_power; + } + + ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS, + reg_val, reg_val & BIT(0), 200, 2000); + if (ret) + goto disable_power; + + /* set MNoC to low power, set PD_NOC_QREQ (bit 0) */ + writel(BIT(0), core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); + + writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE, + core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); + writel(CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); + writel(0x0, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); + +disable_power: + iris_vpu_power_off_hw(core); +} + +static int iris_vpu33_power_off_controller(struct iris_core *core) +{ + u32 xo_rst_tbl_size = core->iris_platform_data->controller_rst_tbl_size; + u32 clk_rst_tbl_size = core->iris_platform_data->clk_rst_tbl_size; + u32 val = 0; + int ret; + + writel(MSK_SIGNAL_FROM_TENSILICA | MSK_CORE_POWER_ON, core->reg_base + CPU_CS_X2RPMH); + + writel(REQ_POWER_DOWN_PREP, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL); + + ret = readl_poll_timeout(core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_STATUS, + val, val & BIT(0), 200, 2000); + if (ret) + goto disable_power; + + writel(0x0, core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_CONTROL); + + ret = readl_poll_timeout(core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_STATUS, + val, val == 0, 200, 2000); + if (ret) + goto disable_power; + + writel(CTL_AXI_CLK_HALT | CTL_CLK_HALT, + core->reg_base + WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG); + writel(RESET_HIGH, core->reg_base + WRAPPER_TZ_QNS4PDXFIFO_RESET); + writel(0x0, core->reg_base + WRAPPER_TZ_QNS4PDXFIFO_RESET); + writel(0x0, core->reg_base + WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG); + + reset_control_bulk_reset(clk_rst_tbl_size, core->resets); + + /* Disable MVP NoC clock */ + val = readl(core->reg_base + AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL); + val |= NOC_HALT; + writel(val, core->reg_base + AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL); + + /* enable MVP NoC reset */ + val = readl(core->reg_base + AON_WRAPPER_MVP_NOC_CORE_SW_RESET); + val |= SW_RESET; + writel(val, core->reg_base + AON_WRAPPER_MVP_NOC_CORE_SW_RESET); + + /* poll AON spare register bit0 to become zero with 50ms timeout */ + ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_SPARE, + val, (val & BIT(0)) == 0, 1000, 50000); + if (ret) + goto disable_power; + + /* enable bit(1) to avoid cvp noc xo reset */ + val = readl(core->reg_base + AON_WRAPPER_SPARE); + val |= BIT(1); + writel(val, core->reg_base + AON_WRAPPER_SPARE); + + reset_control_bulk_assert(xo_rst_tbl_size, core->controller_resets); + + /* De-assert MVP NoC reset */ + val = readl(core->reg_base + AON_WRAPPER_MVP_NOC_CORE_SW_RESET); + val &= ~SW_RESET; + writel(val, core->reg_base + AON_WRAPPER_MVP_NOC_CORE_SW_RESET); + + usleep_range(80, 100); + + reset_control_bulk_deassert(xo_rst_tbl_size, core->controller_resets); + + /* reset AON spare register */ + writel(0, core->reg_base + AON_WRAPPER_SPARE); + + /* Enable MVP NoC clock */ + val = readl(core->reg_base + AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL); + val &= ~NOC_HALT; + writel(val, core->reg_base + AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL); + + iris_disable_unprepare_clock(core, IRIS_CTRL_CLK); + +disable_power: + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); + iris_disable_unprepare_clock(core, IRIS_AXI_CLK); + + return 0; +} + +static u64 iris_vpu3x_calculate_frequency(struct iris_inst *inst, size_t data_size) +{ + struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps; + struct v4l2_format *inp_f = inst->fmt_src; + u32 height, width, mbs_per_second, mbpf; + u64 fw_cycles, fw_vpp_cycles; + u64 vsp_cycles, vpp_cycles; + u32 fps = DEFAULT_FPS; + + width = max(inp_f->fmt.pix_mp.width, inst->crop.width); + height = max(inp_f->fmt.pix_mp.height, inst->crop.height); + + mbpf = NUM_MBS_PER_FRAME(height, width); + mbs_per_second = mbpf * fps; + + fw_cycles = fps * caps->mb_cycles_fw; + fw_vpp_cycles = fps * caps->mb_cycles_fw_vpp; + + vpp_cycles = mult_frac(mbs_per_second, caps->mb_cycles_vpp, (u32)inst->fw_caps[PIPE].value); + /* 21 / 20 is minimum overhead factor */ + vpp_cycles += max(div_u64(vpp_cycles, 20), fw_vpp_cycles); + + /* 1.059 is multi-pipe overhead */ + if (inst->fw_caps[PIPE].value > 1) + vpp_cycles += div_u64(vpp_cycles * 59, 1000); + + vsp_cycles = fps * data_size * 8; + vsp_cycles = div_u64(vsp_cycles, 2); + /* VSP FW overhead 1.05 */ + vsp_cycles = div_u64(vsp_cycles * 21, 20); + + if (inst->fw_caps[STAGE].value == STAGE_1) + vsp_cycles = vsp_cycles * 3; + + return max3(vpp_cycles, vsp_cycles, fw_cycles); +} + +const struct vpu_ops iris_vpu3_ops = { + .power_off_hw = iris_vpu3_power_off_hardware, + .power_off_controller = iris_vpu_power_off_controller, + .calc_freq = iris_vpu3x_calculate_frequency, +}; + +const struct vpu_ops iris_vpu33_ops = { + .power_off_hw = iris_vpu33_power_off_hardware, + .power_off_controller = iris_vpu33_power_off_controller, + .calc_freq = iris_vpu3x_calculate_frequency, +}; diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.c b/drivers/media/platform/qcom/iris/iris_vpu_common.c index fe9896d66848..268e45acaa7c 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_common.c +++ b/drivers/media/platform/qcom/iris/iris_vpu_common.c @@ -211,7 +211,7 @@ skip_power_off: return -EAGAIN; } -static int iris_vpu_power_off_controller(struct iris_core *core) +int iris_vpu_power_off_controller(struct iris_core *core) { u32 val = 0; int ret; @@ -264,7 +264,7 @@ void iris_vpu_power_off(struct iris_core *core) { dev_pm_opp_set_rate(core->dev, 0); core->iris_platform_data->vpu_ops->power_off_hw(core); - iris_vpu_power_off_controller(core); + core->iris_platform_data->vpu_ops->power_off_controller(core); iris_unset_icc_bw(core); if (!iris_vpu_watchdog(core, core->intr_status)) diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.h b/drivers/media/platform/qcom/iris/iris_vpu_common.h index 63fa1fa5a498..93b7fa27be3b 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_common.h +++ b/drivers/media/platform/qcom/iris/iris_vpu_common.h @@ -10,9 +10,11 @@ struct iris_core; extern const struct vpu_ops iris_vpu2_ops; extern const struct vpu_ops iris_vpu3_ops; +extern const struct vpu_ops iris_vpu33_ops; struct vpu_ops { void (*power_off_hw)(struct iris_core *core); + int (*power_off_controller)(struct iris_core *core); u64 (*calc_freq)(struct iris_inst *inst, size_t data_size); }; @@ -22,6 +24,7 @@ void iris_vpu_clear_interrupt(struct iris_core *core); int iris_vpu_watchdog(struct iris_core *core, u32 intr_status); int iris_vpu_prepare_pc(struct iris_core *core); int iris_vpu_power_on(struct iris_core *core); +int iris_vpu_power_off_controller(struct iris_core *core); void iris_vpu_power_off_hw(struct iris_core *core); void iris_vpu_power_off(struct iris_core *core); diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 77d48578ecd2..d305d74bb152 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -438,7 +438,7 @@ static int venus_probe(struct platform_device *pdev) ret = v4l2_device_register(dev, &core->v4l2_dev); if (ret) - goto err_core_deinit; + goto err_hfi_destroy; platform_set_drvdata(pdev, core); @@ -476,24 +476,24 @@ static int venus_probe(struct platform_device *pdev) ret = venus_enumerate_codecs(core, VIDC_SESSION_TYPE_DEC); if (ret) - goto err_venus_shutdown; + goto err_core_deinit; ret = venus_enumerate_codecs(core, VIDC_SESSION_TYPE_ENC); if (ret) - goto err_venus_shutdown; + goto err_core_deinit; ret = pm_runtime_put_sync(dev); if (ret) { pm_runtime_get_noresume(dev); - goto err_dev_unregister; + goto err_core_deinit; } venus_dbgfs_init(core); return 0; -err_dev_unregister: - v4l2_device_unregister(&core->v4l2_dev); +err_core_deinit: + hfi_core_deinit(core, false); err_venus_shutdown: venus_shutdown(core); err_firmware_deinit: @@ -506,9 +506,9 @@ err_runtime_disable: pm_runtime_put_noidle(dev); pm_runtime_disable(dev); pm_runtime_set_suspended(dev); + v4l2_device_unregister(&core->v4l2_dev); +err_hfi_destroy: hfi_destroy(core); -err_core_deinit: - hfi_core_deinit(core, false); err_core_put: if (core->pm_ops->core_put) core->pm_ops->core_put(core); diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index abeeafa86697..b412e0c5515a 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -172,6 +172,7 @@ struct venus_format { * @venus_ver: the venus firmware version * @dump_core: a flag indicating that a core dump is required * @ocs: OF changeset pointer + * @hwmode_dev: a flag indicating that HW_CTRL_TRIGGER is used in clock driver */ struct venus_core { void __iomem *base; @@ -235,6 +236,7 @@ struct venus_core { } venus_ver; unsigned long dump_core; struct of_changeset *ocs; + bool hwmode_dev; }; struct vdec_controls { diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index 33a5a659c0ad..409aa9bd0b5d 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -412,9 +412,17 @@ static int vcodec_control_v4(struct venus_core *core, u32 coreid, bool enable) u32 val; int ret; - if (IS_V6(core)) - return dev_pm_genpd_set_hwmode(core->pmdomains->pd_devs[coreid], !enable); - else if (coreid == VIDC_CORE_ID_1) { + ret = dev_pm_genpd_set_hwmode(core->pmdomains->pd_devs[coreid], !enable); + if (ret == -EOPNOTSUPP) { + core->hwmode_dev = false; + goto legacy; + } + + core->hwmode_dev = true; + return ret; + +legacy: + if (coreid == VIDC_CORE_ID_1) { ctrl = core->wrapper_base + WRAPPER_VCODEC0_MMCC_POWER_CONTROL; stat = core->wrapper_base + WRAPPER_VCODEC0_MMCC_POWER_STATUS; } else { @@ -450,7 +458,7 @@ static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask) vcodec_clks_disable(core, core->vcodec0_clks); - if (!IS_V6(core)) { + if (!core->hwmode_dev) { ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false); if (ret) return ret; @@ -468,7 +476,7 @@ static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask) vcodec_clks_disable(core, core->vcodec1_clks); - if (!IS_V6(core)) { + if (!core->hwmode_dev) { ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false); if (ret) return ret; @@ -491,11 +499,9 @@ static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask) if (ret < 0) return ret; - if (!IS_V6(core)) { - ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true); - if (ret) - return ret; - } + ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true); + if (ret) + return ret; ret = vcodec_clks_enable(core, core->vcodec0_clks); if (ret) @@ -511,11 +517,9 @@ static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask) if (ret < 0) return ret; - if (!IS_V6(core)) { - ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true); - if (ret) - return ret; - } + ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true); + if (ret) + return ret; ret = vcodec_clks_enable(core, core->vcodec1_clks); if (ret) @@ -811,7 +815,7 @@ static int vdec_power_v4(struct device *dev, int on) else vcodec_clks_disable(core, core->vcodec0_clks); - vcodec_control_v4(core, VIDC_CORE_ID_1, false); + ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false); return ret; } @@ -856,7 +860,7 @@ static int venc_power_v4(struct device *dev, int on) else vcodec_clks_disable(core, core->vcodec1_clks); - vcodec_control_v4(core, VIDC_CORE_ID_2, false); + ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false); return ret; } diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index 9f82882b77bc..99ce5fd41577 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -154,14 +154,14 @@ find_format_by_index(struct venus_inst *inst, unsigned int index, u32 type) return NULL; for (i = 0; i < size; i++) { - bool valid; + bool valid = false; if (fmt[i].type != type) continue; if (V4L2_TYPE_IS_OUTPUT(type)) { valid = venus_helper_check_codec(inst, fmt[i].pixfmt); - } else if (V4L2_TYPE_IS_CAPTURE(type)) { + } else { valid = venus_helper_check_format(inst, fmt[i].pixfmt); if (fmt[i].pixfmt == V4L2_PIX_FMT_QC10C && @@ -1110,10 +1110,20 @@ static int vdec_start_output(struct venus_inst *inst) if (inst->codec_state == VENUS_DEC_STATE_SEEK) { ret = venus_helper_process_initial_out_bufs(inst); - if (inst->next_buf_last) + if (ret) + return ret; + + if (inst->next_buf_last) { inst->codec_state = VENUS_DEC_STATE_DRC; - else + } else { inst->codec_state = VENUS_DEC_STATE_DECODING; + + if (inst->streamon_cap) { + ret = venus_helper_queue_dpb_bufs(inst); + if (ret) + return ret; + } + } goto done; } |