diff options
Diffstat (limited to 'drivers/media/platform/qcom/camss')
-rw-r--r-- | drivers/media/platform/qcom/camss/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/platform/qcom/camss/camss-csid-680.c | 422 | ||||
-rw-r--r-- | drivers/media/platform/qcom/camss/camss-csid.c | 4 | ||||
-rw-r--r-- | drivers/media/platform/qcom/camss/camss-csid.h | 1 | ||||
-rw-r--r-- | drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c | 131 | ||||
-rw-r--r-- | drivers/media/platform/qcom/camss/camss-csiphy.c | 28 | ||||
-rw-r--r-- | drivers/media/platform/qcom/camss/camss-csiphy.h | 1 | ||||
-rw-r--r-- | drivers/media/platform/qcom/camss/camss-vfe-680.c | 244 | ||||
-rw-r--r-- | drivers/media/platform/qcom/camss/camss-vfe.c | 6 | ||||
-rw-r--r-- | drivers/media/platform/qcom/camss/camss-vfe.h | 1 | ||||
-rw-r--r-- | drivers/media/platform/qcom/camss/camss.c | 359 | ||||
-rw-r--r-- | drivers/media/platform/qcom/camss/camss.h | 1 |
12 files changed, 1179 insertions, 21 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 { |