Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  camss-csid-780.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module
 *
 * Copyright (c) 2024 Qualcomm Technologies, Inc.
 */

#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/of.h>

#include "camss.h"
#include "camss-csid.h"
#include "camss-csid-780.h"

#define CSID_IO_PATH_CFG0(csid)  (0x4 * (csid))
#define  OUTPUT_IFE_EN   0x100
#define  INTERNAL_CSID   1

#define CSID_RST_CFG   0xC
#define  RST_MODE   BIT(0)
#define  RST_LOCATION   BIT(4)

#define CSID_RST_CMD   0x10
#define  SELECT_HW_RST   BIT(0)
#define  SELECT_IRQ_RST   BIT(2)

#define CSID_IRQ_CMD   0x14
#define  IRQ_CMD_CLEAR   BIT(0)

#define CSID_RUP_AUP_CMD  0x18
#define  CSID_RUP_AUP_RDI(rdi)  ((BIT(4) | BIT(20)) << (rdi))

#define CSID_TOP_IRQ_STATUS  0x7C
#define   TOP_IRQ_STATUS_RESET_DONE BIT(0)

#define CSID_TOP_IRQ_MASK  0x80
#define CSID_TOP_IRQ_CLEAR  0x84
#define CSID_TOP_IRQ_SET  0x88

#define CSID_CSI2_RX_IRQ_STATUS  0x9C
#define CSID_CSI2_RX_IRQ_MASK  0xA0
#define CSID_CSI2_RX_IRQ_CLEAR  0xA4
#define CSID_CSI2_RX_IRQ_SET  0xA8

#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_BUF_DONE_IRQ_SET  0x98

#define CSID_CSI2_RDIN_IRQ_STATUS(rdi) (0xEC + 0x10 * (rdi))
#define  RUP_DONE_IRQ_STATUS  BIT(23)

#define CSID_CSI2_RDIN_IRQ_CLEAR(rdi) (0xF4 + 0x10 * (rdi))
#define CSID_CSI2_RDIN_IRQ_SET(rdi) (0xF8 + 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_PHY_NUM_SEL 20

#define CSID_CSI2_RX_CFG1  0x204
#define  CSI2_RX_CFG1_ECC_CORRECTION_EN BIT(0)
#define  CSI2_RX_CFG1_VC_MODE  BIT(2)

#define CSID_RDI_CFG0(rdi)  (0x500 + 0x100 * (rdi))
#define  RDI_CFG0_TIMESTAMP_EN  BIT(6)
#define  RDI_CFG0_TIMESTAMP_STB_SEL BIT(8)
#define  RDI_CFG0_DECODE_FORMAT  12
#define  RDI_CFG0_DT   16
#define  RDI_CFG0_VC   22
#define  RDI_CFG0_DT_ID   27
#define  RDI_CFG0_EN   BIT(31)

#define CSID_RDI_CTRL(rdi)  (0x504 + 0x100 * (rdi))
#define  RDI_CTRL_START_CMD  BIT(0)

#define CSID_RDI_CFG1(rdi)  (0x510 + 0x100 * (rdi))
#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_PIX_STORE  BIT(10)
#define  RDI_CFG1_PACKING_FORMAT_MIPI BIT(15)

#define CSID_RDI_IRQ_SUBSAMPLE_PATTERN(rdi) (0x548 + 0x100 * (rdi))
#define CSID_RDI_IRQ_SUBSAMPLE_PERIOD(rdi) (0x54C + 0x100 * (rdi))

#define CSI2_RX_CFG0_PHY_SEL_BASE_IDX 1

static void __csid_configure_rx(struct csid_device *csid,
    struct csid_phy_config *phy, int vc)
{
 int 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_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)
{
 int val = 0;

 if (enable)
  val = RDI_CTRL_START_CMD;

 writel(val, csid->base + CSID_RDI_CTRL(rdi));
}

static void __csid_configure_wrapper(struct csid_device *csid)
{
 u32 val;

 /* csid lite doesn't need to configure top register */
 if (csid->res->is_lite)
  return;

 val = OUTPUT_IFE_EN | INTERNAL_CSID;
 writel(val, csid->camss->csid_wrapper_base + CSID_IO_PATH_CFG0(csid->id));
}

static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 vc)
{
 u32 val;
 u8 lane_cnt = csid->phy.lane_cnt;
 /* Source pads matching RDI channels on hardware. Pad 1 -> RDI0, Pad 2 -> RDI1, etc. */
 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);

 if (!lane_cnt)
  lane_cnt = 4;

 /*
 * 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
 */

 u8 dt_id = vc & 0x03;

 val = RDI_CFG0_TIMESTAMP_EN;
 val |= RDI_CFG0_TIMESTAMP_STB_SEL;
 /* note: for non-RDI path, this should be format->decode_format */
 val |= DECODE_FORMAT_PAYLOAD_ONLY << RDI_CFG0_DECODE_FORMAT;
 val |= vc << RDI_CFG0_VC;
 val |= format->data_type << RDI_CFG0_DT;
 val |= dt_id << RDI_CFG0_DT_ID;

 writel(val, csid->base + CSID_RDI_CFG0(vc));

 val = RDI_CFG1_PACKING_FORMAT_MIPI;
 val |= RDI_CFG1_PIX_STORE;
 val |= RDI_CFG1_DROP_H_EN;
 val |= RDI_CFG1_DROP_V_EN;
 val |= RDI_CFG1_CROP_H_EN;
 val |= RDI_CFG1_CROP_V_EN;

 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_EN;
 writel(val, csid->base + CSID_RDI_CFG0(vc));
}

static void csid_configure_stream(struct csid_device *csid, u8 enable)
{
 u8 i;

 __csid_configure_wrapper(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);
  }
}

static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)
{
 return 0;
}

static void csid_subdev_reg_update(struct csid_device *csid, int port_id, bool clear)
{
 if (clear) {
  csid->reg_update &= ~CSID_RUP_AUP_RDI(port_id);
 } else {
  csid->reg_update |= CSID_RUP_AUP_RDI(port_id);
  writel(csid->reg_update, csid->base + CSID_RUP_AUP_CMD);
 }
}

/*
 * 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 val, buf_done_val;
 u8 reset_done;
 int i;

 val = readl(csid->base + CSID_TOP_IRQ_STATUS);
 writel(val, csid->base + CSID_TOP_IRQ_CLEAR);
 reset_done = val & TOP_IRQ_STATUS_RESET_DONE;

 val = readl(csid->base + CSID_CSI2_RX_IRQ_STATUS);
 writel(val, csid->base + CSID_CSI2_RX_IRQ_CLEAR);

 buf_done_val = readl(csid->base + CSID_BUF_DONE_IRQ_STATUS);
 writel(buf_done_val, csid->base + CSID_BUF_DONE_IRQ_CLEAR);

 /* Read and clear IRQ status for each enabled RDI channel */
 for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++)
  if (csid->phy.en_vc & BIT(i)) {
   val = readl(csid->base + CSID_CSI2_RDIN_IRQ_STATUS(i));
   writel(val, csid->base + CSID_CSI2_RDIN_IRQ_CLEAR(i));

   if (val & RUP_DONE_IRQ_STATUS)
    /* clear the reg update bit */
    csid_subdev_reg_update(csid, i, true);

   if (buf_done_val & BIT(BUF_DONE_IRQ_STATUS_RDI_OFFSET + i)) {
    /*
 * For Titan 780, bus done and RUP IRQ have been moved to
 * CSID from VFE. Once CSID received bus done, need notify
 * VFE of this event. Trigger VFE to handle bus done process.
 */

    camss_buf_done(csid->camss, csid->id, i);
   }
  }

 val = IRQ_CMD_CLEAR;
 writel(val, csid->base + CSID_IRQ_CMD);

 if (reset_done)
  complete(&csid->reset_complete);

 return IRQ_HANDLED;
}

/*
 * 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(1, csid->base + CSID_TOP_IRQ_CLEAR);
 writel(1, csid->base + CSID_IRQ_CMD);
 writel(1, csid->base + CSID_TOP_IRQ_MASK);

 for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++)
  if (csid->phy.en_vc & BIT(i)) {
   writel(BIT(BUF_DONE_IRQ_STATUS_RDI_OFFSET + i),
          csid->base + CSID_BUF_DONE_IRQ_CLEAR);
   writel(IRQ_CMD_CLEAR, csid->base + CSID_IRQ_CMD);
   writel(BIT(BUF_DONE_IRQ_STATUS_RDI_OFFSET + i),
          csid->base + CSID_BUF_DONE_IRQ_MASK);
  }

 /* preserve registers */
 val = RST_LOCATION | RST_MODE;
 writel(val, csid->base + CSID_RST_CFG);

 val = SELECT_HW_RST | SELECT_IRQ_RST;
 writel(val, csid->base + CSID_RST_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;
 }

 return 0;
}

static void csid_subdev_init(struct csid_device *csid)
{
 csid->testgen.nmodes = CSID_PAYLOAD_MODE_DISABLED;
}

const struct csid_hw_ops csid_ops_780 = {
 .configure_stream = csid_configure_stream,
 .configure_testgen_pattern = csid_configure_testgen_pattern,
 .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,
};

Messung V0.5
C=92 H=92 G=91

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge