1f0fc808aSLoic Poulain // SPDX-License-Identifier: GPL-2.0 2f0fc808aSLoic Poulain /* 3f0fc808aSLoic Poulain * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module 340 4f0fc808aSLoic Poulain * 5f0fc808aSLoic Poulain * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. 6f0fc808aSLoic Poulain */ 7f0fc808aSLoic Poulain 8f0fc808aSLoic Poulain #include <linux/completion.h> 9*76d2d8f7SLoic Poulain #include <linux/bitfield.h> 10f0fc808aSLoic Poulain #include <linux/interrupt.h> 11f0fc808aSLoic Poulain #include <linux/io.h> 12f0fc808aSLoic Poulain #include <linux/kernel.h> 13f0fc808aSLoic Poulain 14f0fc808aSLoic Poulain #include "camss.h" 15f0fc808aSLoic Poulain #include "camss-csid.h" 16f0fc808aSLoic Poulain #include "camss-csid-gen2.h" 17f0fc808aSLoic Poulain 18f0fc808aSLoic Poulain #define CSID_RST_STROBES (0x010) 19f0fc808aSLoic Poulain #define CSID_RST_SW_REGS BIT(0) 20f0fc808aSLoic Poulain #define CSID_RST_IRQ BIT(1) 21f0fc808aSLoic Poulain #define CSID_RST_IFE_CLK BIT(2) 22f0fc808aSLoic Poulain #define CSID_RST_PHY_CLK BIT(3) 23f0fc808aSLoic Poulain #define CSID_RST_CSID_CLK BIT(4) 24f0fc808aSLoic Poulain 25f0fc808aSLoic Poulain #define CSID_IRQ_STATUS (0x070) 26f0fc808aSLoic Poulain #define CSID_IRQ_MASK (0x074) 27f0fc808aSLoic Poulain #define CSID_IRQ_MASK_RST_DONE BIT(0) 28f0fc808aSLoic Poulain #define CSID_IRQ_CLEAR (0x078) 29f0fc808aSLoic Poulain #define CSID_IRQ_CMD (0x080) 30f0fc808aSLoic Poulain #define CSID_IRQ_CMD_CLEAR BIT(0) 31f0fc808aSLoic Poulain 32f0fc808aSLoic Poulain #define CSID_CSI2_RX_CFG0 (0x100) 33f0fc808aSLoic Poulain #define CSI2_RX_CFG0_NUM_ACTIVE_LANES_MASK GENMASK(1, 0) 34f0fc808aSLoic Poulain #define CSI2_RX_CFG0_DLX_INPUT_SEL_MASK GENMASK(17, 4) 35f0fc808aSLoic Poulain #define CSI2_RX_CFG0_PHY_NUM_SEL_MASK GENMASK(21, 20) 36f0fc808aSLoic Poulain #define CSI2_RX_CFG0_PHY_NUM_SEL_BASE_IDX 1 37f0fc808aSLoic Poulain #define CSI2_RX_CFG0_PHY_TYPE_SEL BIT(24) 38f0fc808aSLoic Poulain 39f0fc808aSLoic Poulain #define CSID_CSI2_RX_CFG1 (0x104) 40f0fc808aSLoic Poulain #define CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN BIT(0) 41f0fc808aSLoic Poulain #define CSI2_RX_CFG1_MISR_EN BIT(6) 42f0fc808aSLoic Poulain #define CSI2_RX_CFG1_CGC_MODE BIT(7) 43f0fc808aSLoic Poulain 44f0fc808aSLoic Poulain #define CSID_RDI_CFG0(rdi) (0x300 + 0x100 * (rdi)) 45f0fc808aSLoic Poulain #define CSID_RDI_CFG0_BYTE_CNTR_EN BIT(0) 46f0fc808aSLoic Poulain #define CSID_RDI_CFG0_TIMESTAMP_EN BIT(1) 47f0fc808aSLoic Poulain #define CSID_RDI_CFG0_DECODE_FORMAT_MASK GENMASK(15, 12) 48f0fc808aSLoic Poulain #define CSID_RDI_CFG0_DECODE_FORMAT_NOP CSID_RDI_CFG0_DECODE_FORMAT_MASK 49f0fc808aSLoic Poulain #define CSID_RDI_CFG0_DT_MASK GENMASK(21, 16) 50f0fc808aSLoic Poulain #define CSID_RDI_CFG0_VC_MASK GENMASK(23, 22) 51f0fc808aSLoic Poulain #define CSID_RDI_CFG0_DTID_MASK GENMASK(28, 27) 52f0fc808aSLoic Poulain #define CSID_RDI_CFG0_ENABLE BIT(31) 53f0fc808aSLoic Poulain 54f0fc808aSLoic Poulain #define CSID_RDI_CTRL(rdi) (0x308 + 0x100 * (rdi)) 55f0fc808aSLoic Poulain #define CSID_RDI_CTRL_HALT_AT_FRAME_BOUNDARY 0 56f0fc808aSLoic Poulain #define CSID_RDI_CTRL_RESUME_AT_FRAME_BOUNDARY 1 57f0fc808aSLoic Poulain 58f0fc808aSLoic Poulain static void __csid_configure_rx(struct csid_device *csid, 59f0fc808aSLoic Poulain struct csid_phy_config *phy, int vc) 60f0fc808aSLoic Poulain { 61f0fc808aSLoic Poulain u32 val; 62f0fc808aSLoic Poulain 63f0fc808aSLoic Poulain val = FIELD_PREP(CSI2_RX_CFG0_NUM_ACTIVE_LANES_MASK, phy->lane_cnt - 1); 64f0fc808aSLoic Poulain val |= FIELD_PREP(CSI2_RX_CFG0_DLX_INPUT_SEL_MASK, phy->lane_assign); 65f0fc808aSLoic Poulain val |= FIELD_PREP(CSI2_RX_CFG0_PHY_NUM_SEL_MASK, 66f0fc808aSLoic Poulain phy->csiphy_id + CSI2_RX_CFG0_PHY_NUM_SEL_BASE_IDX); 67f0fc808aSLoic Poulain writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG0); 68f0fc808aSLoic Poulain 69f0fc808aSLoic Poulain val = CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN; 70f0fc808aSLoic Poulain writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG1); 71f0fc808aSLoic Poulain } 72f0fc808aSLoic Poulain 73f0fc808aSLoic Poulain static void __csid_ctrl_rdi(struct csid_device *csid, int enable, u8 rdi) 74f0fc808aSLoic Poulain { 75f0fc808aSLoic Poulain writel_relaxed(!!enable, csid->base + CSID_RDI_CTRL(rdi)); 76f0fc808aSLoic Poulain } 77f0fc808aSLoic Poulain 78f0fc808aSLoic Poulain static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 vc) 79f0fc808aSLoic Poulain { 80f0fc808aSLoic Poulain struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; 81f0fc808aSLoic Poulain const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats, 82f0fc808aSLoic Poulain csid->res->formats->nformats, 83f0fc808aSLoic Poulain input_format->code); 84f0fc808aSLoic Poulain u8 lane_cnt = csid->phy.lane_cnt; 85f0fc808aSLoic Poulain u8 dt_id; 86f0fc808aSLoic Poulain u32 val; 87f0fc808aSLoic Poulain 88f0fc808aSLoic Poulain if (!lane_cnt) 89f0fc808aSLoic Poulain lane_cnt = 4; 90f0fc808aSLoic Poulain 91f0fc808aSLoic Poulain /* 92f0fc808aSLoic Poulain * DT_ID is a two bit bitfield that is concatenated with 93f0fc808aSLoic Poulain * the four least significant bits of the five bit VC 94f0fc808aSLoic Poulain * bitfield to generate an internal CID value. 95f0fc808aSLoic Poulain * 96f0fc808aSLoic Poulain * CSID_RDI_CFG0(vc) 97f0fc808aSLoic Poulain * DT_ID : 28:27 98f0fc808aSLoic Poulain * VC : 26:22 99f0fc808aSLoic Poulain * DT : 21:16 100f0fc808aSLoic Poulain * 101f0fc808aSLoic Poulain * CID : VC 3:0 << 2 | DT_ID 1:0 102f0fc808aSLoic Poulain */ 103f0fc808aSLoic Poulain dt_id = vc & 0x03; 104f0fc808aSLoic Poulain 105f0fc808aSLoic Poulain val = CSID_RDI_CFG0_DECODE_FORMAT_NOP; /* only for RDI path */ 106f0fc808aSLoic Poulain val |= FIELD_PREP(CSID_RDI_CFG0_DT_MASK, format->data_type); 107f0fc808aSLoic Poulain val |= FIELD_PREP(CSID_RDI_CFG0_VC_MASK, vc); 108f0fc808aSLoic Poulain val |= FIELD_PREP(CSID_RDI_CFG0_DTID_MASK, dt_id); 109f0fc808aSLoic Poulain 110f0fc808aSLoic Poulain if (enable) 111f0fc808aSLoic Poulain val |= CSID_RDI_CFG0_ENABLE; 112f0fc808aSLoic Poulain 113f0fc808aSLoic Poulain dev_dbg(csid->camss->dev, "CSID%u: Stream %s (dt:0x%x vc=%u)\n", 114f0fc808aSLoic Poulain csid->id, enable ? "enable" : "disable", format->data_type, vc); 115f0fc808aSLoic Poulain 116f0fc808aSLoic Poulain writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc)); 117f0fc808aSLoic Poulain } 118f0fc808aSLoic Poulain 119f0fc808aSLoic Poulain static void csid_configure_stream(struct csid_device *csid, u8 enable) 120f0fc808aSLoic Poulain { 121f0fc808aSLoic Poulain int i; 122f0fc808aSLoic Poulain 123f0fc808aSLoic Poulain for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++) { 124f0fc808aSLoic Poulain if (csid->phy.en_vc & BIT(i)) { 125f0fc808aSLoic Poulain __csid_configure_rdi_stream(csid, enable, i); 126f0fc808aSLoic Poulain __csid_configure_rx(csid, &csid->phy, i); 127f0fc808aSLoic Poulain __csid_ctrl_rdi(csid, enable, i); 128f0fc808aSLoic Poulain } 129f0fc808aSLoic Poulain } 130f0fc808aSLoic Poulain } 131f0fc808aSLoic Poulain 132f0fc808aSLoic Poulain static int csid_reset(struct csid_device *csid) 133f0fc808aSLoic Poulain { 134f0fc808aSLoic Poulain unsigned long time; 135f0fc808aSLoic Poulain 136f0fc808aSLoic Poulain writel_relaxed(CSID_IRQ_MASK_RST_DONE, csid->base + CSID_IRQ_MASK); 137f0fc808aSLoic Poulain writel_relaxed(CSID_IRQ_MASK_RST_DONE, csid->base + CSID_IRQ_CLEAR); 138f0fc808aSLoic Poulain writel_relaxed(CSID_IRQ_CMD_CLEAR, csid->base + CSID_IRQ_CMD); 139f0fc808aSLoic Poulain 140f0fc808aSLoic Poulain reinit_completion(&csid->reset_complete); 141f0fc808aSLoic Poulain 142f0fc808aSLoic Poulain /* Reset with registers preserved */ 143f0fc808aSLoic Poulain writel(CSID_RST_IRQ | CSID_RST_IFE_CLK | CSID_RST_PHY_CLK | CSID_RST_CSID_CLK, 144f0fc808aSLoic Poulain csid->base + CSID_RST_STROBES); 145f0fc808aSLoic Poulain 146f0fc808aSLoic Poulain time = wait_for_completion_timeout(&csid->reset_complete, 147f0fc808aSLoic Poulain msecs_to_jiffies(CSID_RESET_TIMEOUT_MS)); 148f0fc808aSLoic Poulain if (!time) { 149f0fc808aSLoic Poulain dev_err(csid->camss->dev, "CSID%u: reset timeout\n", csid->id); 150f0fc808aSLoic Poulain return -EIO; 151f0fc808aSLoic Poulain } 152f0fc808aSLoic Poulain 153f0fc808aSLoic Poulain dev_dbg(csid->camss->dev, "CSID%u: reset done\n", csid->id); 154f0fc808aSLoic Poulain 155f0fc808aSLoic Poulain return 0; 156f0fc808aSLoic Poulain } 157f0fc808aSLoic Poulain 158f0fc808aSLoic Poulain static irqreturn_t csid_isr(int irq, void *dev) 159f0fc808aSLoic Poulain { 160f0fc808aSLoic Poulain struct csid_device *csid = dev; 161f0fc808aSLoic Poulain u32 val; 162f0fc808aSLoic Poulain 163f0fc808aSLoic Poulain val = readl_relaxed(csid->base + CSID_IRQ_STATUS); 164f0fc808aSLoic Poulain writel_relaxed(val, csid->base + CSID_IRQ_CLEAR); 165f0fc808aSLoic Poulain writel_relaxed(CSID_IRQ_CMD_CLEAR, csid->base + CSID_IRQ_CMD); 166f0fc808aSLoic Poulain 167f0fc808aSLoic Poulain if (val & CSID_IRQ_MASK_RST_DONE) 168f0fc808aSLoic Poulain complete(&csid->reset_complete); 169f0fc808aSLoic Poulain else 170f0fc808aSLoic Poulain dev_warn_ratelimited(csid->camss->dev, "Spurious CSID interrupt\n"); 171f0fc808aSLoic Poulain 172f0fc808aSLoic Poulain return IRQ_HANDLED; 173f0fc808aSLoic Poulain } 174f0fc808aSLoic Poulain 175f0fc808aSLoic Poulain static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val) 176f0fc808aSLoic Poulain { 177f0fc808aSLoic Poulain return -EOPNOTSUPP; /* Not part of CSID */ 178f0fc808aSLoic Poulain } 179f0fc808aSLoic Poulain 180f0fc808aSLoic Poulain static void csid_subdev_init(struct csid_device *csid) {} 181f0fc808aSLoic Poulain 182f0fc808aSLoic Poulain const struct csid_hw_ops csid_ops_340 = { 183f0fc808aSLoic Poulain .configure_testgen_pattern = csid_configure_testgen_pattern, 184f0fc808aSLoic Poulain .configure_stream = csid_configure_stream, 185f0fc808aSLoic Poulain .hw_version = csid_hw_version, 186f0fc808aSLoic Poulain .isr = csid_isr, 187f0fc808aSLoic Poulain .reset = csid_reset, 188f0fc808aSLoic Poulain .src_pad_code = csid_src_pad_code, 189f0fc808aSLoic Poulain .subdev_init = csid_subdev_init, 190f0fc808aSLoic Poulain }; 191