【QCOM】CAMSS架构中CSi与CSIPHY驱动结构

框架总览

源码仓库:基于树莓派代码仓库,分析qcom的camera驱动框架,此代码并非高通最新代码,主要目的是分析学习QCOM的CSI与CSIPHY的驱动框架

https://github.com/raspberrypi/linux

内核版本:6.12

驱动代码路径:linux\drivers\media\platform\qcom

CSIPHY层级架构

camss-csiphy.c是"统一接口层",camss-csiphy-3ph-1-0.c和 camss-csiphy-2ph-1-0.c是具体寄存器驱动层"

层级关系图

cpp 复制代码
CAMSS 框架层
  └─ camss.c
      └─ 按 SoC 资源选择 hw_ops
         ├─ csiphy_ops_2ph_1_0  -> camss-csiphy-2ph-1-0.c
         └─ csiphy_ops_3ph_1_0  -> camss-csiphy-3ph-1-0.c

CSIPHY 通用层(框架/胶水层)
  └─ camss-csiphy.c
      ├─ V4L2 subdev 注册/格式协商/电源时钟IRQ管理
      └─ 通过 csiphy->res->hw_ops 调具体硬件实现

CSIPHY 硬件实现层(寄存器层)
  ├─ camss-csiphy-2ph-1-0.c   (2-phase PHY 寄存器实现)
  └─ camss-csiphy-3ph-1-0.c   (3-phase PHY 寄存器实现)

调用关系图

cpp 复制代码
userspace STREAMON / power on
    -> camss-csiphy.c
       -> csiphy_set_power()
          -> hw_ops->reset()
          -> hw_ops->hw_version_read()
       -> csiphy_set_stream()
          -> csiphy_stream_on()
             -> hw_ops->get_lane_mask()
             -> hw_ops->lanes_enable()   // 真正写寄存器
          -> csiphy_stream_off()
             -> hw_ops->lanes_disable()  // 真正写寄存器
       -> IRQ
          -> hw_ops->isr()

camss-csiphy

csiphy属于物理层,负责把线上的数据正确的收下来

核心数据结构

cpp 复制代码
// 支持media bus code与bpp映射,用于时钟/链路频率计算
struct csiphy_format_info {
	u32 code;                               // 媒体总线代码,V4L2标准的格式标识符
	u8 bpp;                                 // 每像素位数(Bits Per Pixel),用于带宽和时钟计算
};

// csiphy支持的格式
struct csiphy_formats {
	unsigned int nformats;                  // 支持的格式数量
	const struct csiphy_format_info *formats; // 格式信息数组,定义所有支持的格式
};

// 当前链路配置
struct csiphy_config {
	u8 combo_mode;                          // 组合模式,可能支持多种工作模式组合
	u8 csid_id;                             // 对应的CSI-DC(解码器)ID,建立PHY与DC的关联
	struct csiphy_csi2_cfg *csi2;           // CSI-2配置指针,包含具体的CSI-2参数
};

struct csiphy_csi2_cfg {
	struct csiphy_lanes_cfg lane_cfg;       // 通道配置,定义CSI-2接口的通道布局
};

// MIPI-Lane描述,直接影响lane_mask和Lane使能寄存器
struct csiphy_lanes_cfg {
	int num_data;                           // 数据通道数量,指定使用的数据通道数目
	struct csiphy_lane *data;               // 数据通道数组指针,指向具体的数据通道配置
	struct csiphy_lane clk;                 // 时钟通道配置,CSI-2标准的时钟通道
};

// 单个MIPI通道信息
struct csiphy_lane {
	u8 pos;                                 // 通道位置/编号,在物理接口中的实际位置
	u8 pol;                                 // 通道极性,表示差分信号的正负极性配置
};


// 硬件抽象接口
struct csiphy_hw_ops {
	/*
	 * csiphy_get_lane_mask - 计算CSI2通道掩码配置参数
	 * @lane_cfg - CSI2通道配置
	 *
	 * 返回通道掩码
	 */
	u8 (*get_lane_mask)(struct csiphy_lanes_cfg *lane_cfg);
	
	void (*hw_version_read)(struct csiphy_device *csiphy, // 读取硬件版本信息
				struct device *dev);
				
	void (*reset)(struct csiphy_device *csiphy);          // 复位CSI-PHY硬件
	
	void (*lanes_enable)(struct csiphy_device *csiphy,    // 启用数据通道
			     struct csiphy_config *cfg,
			     s64 link_freq, u8 lane_mask);
			     
	void (*lanes_disable)(struct csiphy_device *csiphy,  // 禁用数据通道
			      struct csiphy_config *cfg);   
			      
	irqreturn_t (*isr)(int irq, void *dev);              // 中断服务例程
};

// CSI-PHY运行时核心对象
struct csiphy_device {
	struct camss *camss;                    // 指向CAMSS(摄像头子系统)主控制器的指针
	u8 id;                                  // CSI-PHY设备ID,用于标识不同的PHY实例
	struct v4l2_subdev subdev;              // V4L2子设备结构,提供V4L2框架接口
	struct media_pad pads[MSM_CSIPHY_PADS_NUM]; // 媒体垫片数组,用于media framework连接
	void __iomem *base;                     // 寄存器基地址,指向CSI-PHY硬件寄存器的内存映射地址
	void __iomem *base_clk_mux;             // 时钟多路复用器寄存器基地址
	u32 irq;                                // 中断号,用于处理CSI-PHY硬件中断
	char irq_name[30];                      // 中断名称字符串
	struct camss_clock *clock;              // 时钟数组,管理PHY所需的时钟资源
	bool *rate_set;                         // 时钟频率设置状态数组
	int nclocks;                            // 时钟数量
	u32 timer_clk_rate;                     // 定时器时钟频率
	struct csiphy_config cfg;               // 当前配置,保存当前的PHY配置参数
	struct v4l2_mbus_framefmt fmt[MSM_CSIPHY_PADS_NUM]; // 当前格式数组,保存各pad的帧格式
	const struct csiphy_subdev_resources *res; // 资源指针,指向具体的硬件资源实现
};

// 平台资源绑定点,核心资源是hw_ops+formats两张表
struct csiphy_subdev_resources {
	const struct csiphy_hw_ops *hw_ops;     // 硬件操作函数表,提供不同芯片型号的具体硬件操作实现
	const struct csiphy_formats *formats;   // 格式支持表,定义支持的媒体总线格式及其位深信息
};

核心功能函数

cpp 复制代码
格式与带宽: 
csiphy_get_bpp()、csiphy_set_clock_rates() 根据像素格式 + lane 数 + link freq 选择并设置时钟。

电源管理: 
csiphy_set_power() 完成 pm_runtime、开关时钟、IRQ 使能、调用 hw_ops->reset/hw_version_read。

流控制: 
csiphy_stream_on() 计算 lane_mask、读取链路频率、配置 base_clk_mux(旧平台)后调用 hw_ops->lanes_enable();csiphy_stream_off() 调 hw_ops->lanes_disable();csiphy_set_stream() 做开关分发。
格式协商: __csiphy_get_format()、csiphy_try_format()、csiphy_enum_mbus_code()、csiphy_enum_frame_size()、csiphy_get_format()、csiphy_set_format()、csiphy_init_formats()。

初始化资源: 
msm_csiphy_subdev_init() ioremap、申请 IRQ、解析 clocks 与可调速时钟 rate_set[]。

媒体图连接:
csiphy_link_setup() 在 CSIPHY -> CSID 建链时写入 cfg.csid_id。

实体注册:
msm_csiphy_register_entity() / msm_csiphy_unregister_entity() 负责 v4l2 subdev 与 media entity 生命周期。

关键调用路径:

cpp 复制代码
Power On: csiphy_set_power() → hw_ops->reset() → hw_ops->hw_version_read()

Stream On: csiphy_set_stream() → csiphy_stream_on() → hw_ops->get_lane_mask() → hw_ops->lanes_enable()(真正寄存器配置在 camss-csiphy-2ph-1-0.c 或 camss-csiphy-3ph-1-0.c)

Stream Off: csiphy_set_stream() → csiphy_stream_off() → hw_ops->lanes_disable()

IRQ: devm_request_irq(..., hw_ops->isr, ...) → 中断逻辑在 2ph/3ph 文件

camss-csiphy-3ph-1-0

CSIPHY主要配置的是MIPI D-PHY物理层参数,比如lane,时序,HS/LP收发行为等

CSI-2包层参数,比如VC、DT、解码格式等在CSID中配置

CSIPHY侧可配置的参数

  • Lane 数量与 lane 位置映射:来自 cfg->csi2->lane_cfg.num_datadata[i].pos,用于生成 lane_mask、配置启用哪些数据 lane。
  • PHY 到 CSID 路由选择:cfg.csid_id(在 camss-csiphy.c 的 csiphy_link_setup() 建链时确定),并在 base_clk_mux 平台上写入 mux 选择。
  • Combo mode 路由行为:cfg.combo_mode 影响 mux 位域选择逻辑。
  • 链路频率相关参数:link_freq(由上游 sensor pixel rate + bpp + lane 数推导),用于后续时序计算。
  • CSIPHY 定时器时钟:timer_clk_rate(根据 link_freq 选频并 clk_set_rate),直接影响 settle count 计算精度。
  • HS settle 计数:csiphy_settle_cnt_calc() 算出 settle_cnt,写到 lane 配置(gen2 表驱动项 CSIPHY_SETTLE_CNT_LOWER_BYTE 或 gen1 的 LNn_CFG3)。
  • 每Lane的物理层时序/电气项:
    • 接收延迟参数(SWI_REC_DLY_PRG)
    • LP 接收使能(LP_REC_EN_INT)
    • HS 检测/终端/均衡(T_HS_DTERM、HS_REC_EQ_FQ_INT)
    • T_INIT / T_WAKEUP
    • SOT symbol
    • HS 终端阻抗
    • 时钟 lane miss 检测阈值(含 660 特例)
  • 公共控制项:
    • lane/clock 使能(COMMON_CTRL5
    • PHY 上电(COMMON_CTRL6_COMMON_PWRDN_B
    • 复位(COMMON_CTRL0
    • IRQ mask/ack 相关控制(COMMON_CTRL1022..32

CSIPHY参数表 - 物理层

参数 归属 代码位置 作用
num_data / data[i].pos CSIPHY camss-csiphy-3ph-1-0.c ::csiphy_get_lane_mask() ::csiphy_lanes_enable() 决定启用几条 data lane 及 lane 映射
combo_mode / csid_id CSIPHY camss-csiphy.c ::csiphy_stream_on() 用于 base_clk_mux 路由到目标 CSID
link_freq CSIPHY camss-csiphy.c ::csiphy_stream_on() 来自上游链路频率,驱动后续时序参数
timer_clk_rate CSIPHY camss-csiphy.c ::csiphy_set_clock_rates() PHY 定时器时钟,影响 settle_cnt 计算
settle_cnt CSIPHY camss-csiphy-3ph-1-0.c ::csiphy_settle_cnt_calc() + csiphy_gen1/2_config_lanes() 对应 D-PHY HS settle 时序
T_INIT / T_WAKEUP CSIPHY csiphy_gen1_config_lanes()LNn_CFG7 / LNn_CFG9 D-PHY 初始化/唤醒时序
HS 接收电气参数 CSIPHY LNn_CFG5T_HS_DTERMHS_REC_EQ_FQ_INT HS 终止与均衡行为
SOT / 终端阻抗 / 时钟 miss CSIPHY LNn_CSI_LANE_CTRL15 LNn_TEST_IMP LNn_CFG4 起始符检测、电气阻抗、时钟异常阈值
公共开关 CSIPHY COMMON_CTRL5/6/0 lane 时钟使能、公共上电、复位
中断控制 CSIPHY csiphy_isr() + COMMON_CTRL10/22..32 状态读取、ACK、清理

不在CSIPHY中的协议参数:

  • VC(Virtual Channel)
  • DT(Data Type)
  • payload decode/packing 格式
  • RDI/像素路径的数据路由

以上协议配置在CSID配置中,也就是CSI-2包解析/解复用层

参数意义说明

settle_cnt:

D-PHY的一个重要时序参数,定义了

  • 从低功耗(LP)模式切换到高速(HS)模式后,信号需要多少时间才能稳定
  • 这个时间必须足够长,以确保接收端能够正确识别高速数据
  • 如果settle时间不够,会导致数据采样错误,影响图像质量

combo_mode:

不是MIPI CSI-2标准协议的属于,是芯片原厂在设计和实现CSIPHY时针对硬件资源共享衍生出的一个工程配置概念

  • 单摄独占模式:一个物理MIPI PHY接口完全分配给一个SENSO使用,该 PHY 的所有数据通道(比如 4 个 Lane)和时钟通道(Clock Lane)都服务于这一个摄像头
  • 组合模式:两个摄像头 Sensor 共用同一个物理 MIPI PHY 接口,物理接口上的有限通道(比如 4 个 Lane)会被拆分给两个摄像头使用。例如,主摄占用 2 个数据 Lane,副摄占用另外 2 个数据 Lane,或者共享时钟通道

camss-csiphy-2ph-1-0

camss-csiphy-2ph-1-0和camss-csiphy-3ph-1-0都实现同一套hw_ops接口,被camss-csiphy.c统一调用

但是相比3ph,2ph的寄存器少,流程直接,参数固定,lanes_enable主要写T_INIT/T_WAKEUP,PWR_CFG和每Lane的CFG2/CFG3和中断寄存器

settle_cnt的计算公式和中断处理差异也比较大

CSID层级架构

相关源文件:camss-csid.c,camss-csid-gen2.c,camss-csid-gen2.c,camss-csid-4-7.c

CSID参数表 - 协议层

参数 归属 代码位置 作用
VC(Virtual Channel) CSID camss-csid-gen2.c ::__csid_configure_rdi_stream() 选择包的虚拟通道
DT(Data Type) CSID 同上(RDI_CFG0_DATA_TYPE ) 或 gen1 的 CID_LUT 按数据类型分流
Decode / packing 格式 CSID camss-csid-4-7.c ::csid_configure_stream() camss-csid-gen2.c 控制 RAW/YUV 解码与打包方式
RDI 使能/路由 CSID __csid_ctrl_rdi() RDI_CFG0_ENABLE 决定输出到哪个 RDI 通道

camss-csid

CSID属于链路层,负责把收到的CSI-2包按VC/DT解出来并路由,属于协议/解码层

关键数据结构

cpp 复制代码
// 媒体格式到 CSI 数据类型/解码格式的映射
struct csid_format_info {
	u32 code;            // V4L2 format code
	u8 data_type;        // 对应的CSI数据类型
	u8 decode_format;    // CSID内部解码格式,配置寄存器用
	u8 bpp;              // 每像素位数,用于时钟频率计算
	u8 spp; /* bus samples per pixel */   // 每像素采样数,用于时钟频率计算
 };

// CSID支持的格式列表
struct csid_formats {
	unsigned int nformats;                   // 支持的格式数量
	const struct csid_format_info *formats;  // 格式数组
};

// 内建测试图案发生器配置
struct csid_testgen_config {
	enum csid_testgen_mode mode;   // 模式
	const char * const*modes;      // 模式字符串数组,和mode枚举值一一对应
	u8 nmodes;                     // 支持的模式数量  
	u8 enabled;                    // 是否启用
};

// CSID 侧接收 PHY 拓扑参数,连哪个 csiphy、lane 数、lane 分配、启用 VC 位图
struct csid_phy_config {
	u8 csiphy_id;       // csiphy id
	u8 lane_cnt;	    // lane数量
	u32 lane_assign;    // lane分配,bit0-3分别代表lane0-3,值为0/1/2分别代表不使用/数据/时钟
	u32 en_vc;          // 是否启用VC位图,bit0-3分别代表VC0-3
	u8 need_vc_update;  // 是否需要更新VC位图,配合en_vc使用,表示当前VC位图是否已是最新的
};

// CSID硬件抽象接口
struct csid_hw_ops {
	/*
	 * configure_stream - Configures and starts CSID input stream
	 * @csid: CSID device
	 */
	// 真实寄存器流配置入口
	void (*configure_stream)(struct csid_device *csid, u8 enable);

	/*
	 * configure_testgen_pattern - Validates and configures output pattern mode
	 * of test pattern generator
	 * @csid: CSID device
	 */
	// 测试图案发生器配置入口,负责验证和配置测试图案发生器的模式
	int (*configure_testgen_pattern)(struct csid_device *csid, s32 val);

	/*
	 * hw_version - Read hardware version register from hardware
	 * @csid: CSID device
	 */
	// 读取硬件版本寄存器
	u32 (*hw_version)(struct csid_device *csid);

	/*
	 * isr - CSID module interrupt service routine
	 * @irq: Interrupt line
	 * @dev: CSID device
	 *
	 * Return IRQ_HANDLED on success
	 */
	// 中断处理
	irqreturn_t (*isr)(int irq, void *dev);

	/*
	 * reset - Trigger reset on CSID module and wait to complete
	 * @csid: CSID device
	 *
	 * Return 0 on success or a negative error code otherwise
	 */
	// 复位处理
	int (*reset)(struct csid_device *csid);

	/*
	 * src_pad_code - Pick an output/src format based on the input/sink format
	 * @csid: CSID device
	 * @sink_code: The sink format of the input
	 * @match_format_idx: Request preferred index, as defined by subdevice csid_format.
	 *	Set @match_code to 0 if used.
	 * @match_code: Request preferred code, set @match_format_idx to 0 if used
	 *
	 * Return 0 on failure or src format code otherwise
	 */
	// 根据输入/接收格式选择输出/源格式
	u32 (*src_pad_code)(struct csid_device *csid, u32 sink_code,
			    unsigned int match_format_idx, u32 match_code);

	/*
	 * subdev_init - Initialize CSID device according for hardware revision
	 * @csid: CSID device
	 */
	// 子设备初始化
	void (*subdev_init)(struct csid_device *csid);
};

// 平台资源绑定点
struct csid_subdev_resources {
	bool is_lite;                             // 是否为CSID lite版本,CSID lite版本功能受限,寄存器布局也不同
	const struct csid_hw_ops *hw_ops;         // 硬件抽象接口函数表,不同版本CSID实现不同的hw_ops
	const struct parent_dev_ops *parent_dev_ops;   // 获取父设备资源的接口函数表,CSID寄存器地址在父设备地址基础上有偏移,需要通过这个接口获取父设备地址
	const struct csid_formats *formats;       // 支持的格式列表,不同版本CSID实现不同的formats
};


// CSID 运行时主对象,主要包括硬件资源,格式状态,phy配置等
struct csid_device {
	struct camss *camss;
	u8 id;                                       // CSID模块id,0/1/2分别代表CSID0/1/2,3代表CSID lite
	struct v4l2_subdev subdev;                  // V4L2子设备结构体,注册到V4L2框架用
	struct media_pad pads[MSM_CSID_PADS_NUM];   // CSID的sink pad和多个src pad
	void __iomem *base;                     // 寄存器基地址
	u32 irq;                                // 中断号
	char irq_name[30];                      // 中断名称,用于request_irq
	struct camss_clock *clock;              // 时钟数组
	int nclocks;                            // 时钟数量
	struct regulator_bulk_data *supplies;   // 电源供应数组
	int num_supplies;                       // 电源供应数量
	struct completion reset_complete;       // reset完成的同步机制
	struct csid_testgen_config testgen;     // 内建测试图案发生器配置
	struct csid_phy_config phy;                         // 侧接收PHY配置
	struct v4l2_mbus_framefmt fmt[MSM_CSID_PADS_NUM];   // 当前格式状态,包含sink pad和src pad的格式
	struct v4l2_ctrl_handler ctrls;         // V4L2控制处理器,用于测试图案发生器的模式控制
	struct v4l2_ctrl *testgen_mode;         // 测试图案发生器模式控制
	const struct csid_subdev_resources *res; // 平台资源指针,包含硬件抽象接口函数表和支持的格式列表等
};

关键数据结构的功能定位:

csid_device - 全局状态中心

csid_phy_config - 链路拓扑核心

csid_hw_ops - 功能分派核心

结构关系链路:

资源注入:camss平台资源 -> csid_subdev_resources->csid_device.res

运行时对象:csid_device持有Phy,testfen,fmt,ctrls

硬件实现分派:csid_device.res -> hw_ops指向csid_ops_4_1/csid_ops_4_7/csid_ops_gen2

调用流:set_power/set_stream(通用层) -> hw_ops

核心功能函数

功能分组

格式能力与映射

cpp 复制代码
// 在给定 codes[] 中按"优先匹配 match_code,否则按 match_format_idx"选择输出格式码
u32 csid_find_code(u32 *codes, unsigned int ncodes,
		   unsigned int match_format_idx, u32 match_code)

// 在 csid_format_info 表中查找与 code 对应的格式描述
const struct csid_format_info *csid_get_fmt_entry(const struct csid_format_info *formats,
						  unsigned int nformats,
						  u32 code)
// 规范化并校验某个 pad 的请求格式,码流、尺寸、field/colorspace
static void csid_try_format(struct csid_device *csid,
			    struct v4l2_subdev_state *sd_state,
			    unsigned int pad,
			    struct v4l2_mbus_framefmt *fmt,
			    enum v4l2_subdev_format_whence which)

// 枚举 pad 支持的 mbus format code
static int csid_enum_mbus_code(struct v4l2_subdev *sd,
			       struct v4l2_subdev_state *sd_state,
			       struct v4l2_subdev_mbus_code_enum *code)

// 枚举某个 code 的最小/最大帧尺寸,通过try_format 推导
static int csid_enum_frame_size(struct v4l2_subdev *sd,
				struct v4l2_subdev_state *sd_state,
				struct v4l2_subdev_frame_size_enum *fse)

// 读取指定 pad 的 TRY/ACTIVE 当前格式并返回
static int csid_get_format(struct v4l2_subdev *sd,
			   struct v4l2_subdev_state *sd_state,
			   struct v4l2_subdev_format *fmt)

// 设定并规范化指定 pad 的 TRY/ACTIVE 格式
static int csid_set_format(struct v4l2_subdev *sd,
			   struct v4l2_subdev_state *sd_state,
			   struct v4l2_subdev_format *fmt)

// 打开节点或初始化时设置默认格式,比如UYVY 1920*1080
static int csid_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)

时钟/电源/流控

cpp 复制代码
// 根据当前格式 bpp、lane 数与链路频率计算并设置 CSID 相关时钟频率
static int csid_set_clock_rates(struct csid_device *csid)

// CSID 上下电总入口:runtime PM、regulator、clocks、irq 使能/关闭
// 上电后调用 hw_ops->reset() 与 hw_ops->hw_version(),下电时反向清理,并执行parent_dev_ops->put()
static int csid_set_power(struct v4l2_subdev *sd, int on)

// 开关流入口
static int csid_set_stream(struct v4l2_subdev *sd, int enable)

测试图案控制 - 如果CSID已经与CSIPHY在真实链路上,不允许开testgen,真正的寄存器配置走csid->res->hw_ops->configure_testgen_pattern

cpp 复制代码
// 设置 testgen 开关与模式入口
static int csid_set_test_pattern(struct csid_device *csid, s32 value)

// V4L2 控件写入回调
static int csid_s_ctrl(struct v4l2_ctrl *ctrl)

链路与拓扑管理

cpp 复制代码
// 将 csiphy 的 data lane 位置编码为 CSID 使用的 lane assignment 位域
static u32 csid_get_lane_assign(struct csiphy_lanes_cfg *lane_cfg)

// media graph 链路建立/断开回调
// sink 侧:从远端 CSIPHY 同步 csiphy_id/lane_cnt/lane_assign
// source 侧:维护 phy.en_vc 位图,并置 need_vc_update=true 触发后续重配置
static int csid_link_setup(struct media_entity *entity,
			   const struct media_pad *local,
			   const struct media_pad *remote, u32 flags)

设备初始化与注册

cpp 复制代码
// 初始化 csid_device 运行资源:内存映射、IRQ、clock、regulator、completion 等
// 绑定平台资源并执行 hw_ops->subdev_init()
int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
			 const struct camss_subdev_resources *res, u8 id)

// 注册 V4L2 subdev 与 media entity/pads
int msm_csid_register_entity(struct csid_device *csid,
			     struct v4l2_device *v4l2_dev)

// 反注册 subdev,清理 media entity 与控件资源
void msm_csid_unregister_entity(struct csid_device *csid)

// 从 media entity 反查对应 CSID 硬件实例 ID
void msm_csid_get_csid_id(struct media_entity *entity, u8 *id)

// 判断当前 CSID 实例是否为 lite 版本,主要影响寄存器的布局与能力
inline bool csid_is_lite(struct csid_device *csid)

v4l2/media ops表

cpp 复制代码
static const struct v4l2_subdev_core_ops csid_core_ops = {
	.s_power = csid_set_power,      // 电源状态切换入口
	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,   // 控件事件订阅管理
	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
};

static const struct v4l2_subdev_video_ops csid_video_ops = {
	.s_stream = csid_set_stream,      // 视频流启停入口
};

// pad 级格式协商能力
static const struct v4l2_subdev_pad_ops csid_pad_ops = {
	.enum_mbus_code = csid_enum_mbus_code,
	.enum_frame_size = csid_enum_frame_size,
	.get_fmt = csid_get_format,
	.set_fmt = csid_set_format,
};

// 汇总 core/video/pad 三类 subdev 回调
static const struct v4l2_subdev_ops csid_v4l2_ops = {
	.core = &csid_core_ops,
	.video = &csid_video_ops,
	.pad = &csid_pad_ops,
};

static const struct media_entity_operations csid_media_ops = {
	.link_setup = csid_link_setup,               // 图连接状态变化入口
	.link_validate = v4l2_subdev_link_validate,  // 链路参数一致性校验
};
关键函数

上电链路函数:csid_set_power

负责pm_runtime,regulator,clock,IRQ,hw_ops->reset,hw_ops->hw_version

开流函数:csid_set_stream

首先校验testgen/链路状态,然后在need_vc_update时调用hw_ops->configure_stream

格式协商函数:csid_try_format,csid_set_format,csid_enum_mbus_code

sink/src格式联动,testgen开关影响src格式策略

链路状态函数:csid_link_setup

sink链路建立时同步csiphy_id,lane_cnt,lane_assign

source链路建立/断开时维持phy.en_vc位图与need_vc_update

寄存器资源函数:msm_csid_subdev_init

ioremap、irq request、clock/regulator构建,reset_compele初始化

**节点声明周期函数:msm_csid_register_entity,msm_csid_unregister_entity

**subdev、ctrl、media entity、pads全部注册与清理

逻辑时序

STREAMON主时序(从CSID角度)

cpp 复制代码
Userspace
  -> V4L2 core
    -> csid_core_ops.s_power = csid_set_power(on=1)
       -> parent_dev_ops->get(camss, csid->id)
       -> pm_runtime_resume_and_get()
       -> regulator_bulk_enable()
       -> csid_set_clock_rates()
       -> camss_enable_clocks()
       -> csid->phy.need_vc_update = true
       -> enable_irq(csid->irq)
       -> csid->res->hw_ops->reset(csid)
       -> csid->res->hw_ops->hw_version(csid)

Userspace
  -> V4L2 core
    -> csid_video_ops.s_stream = csid_set_stream(enable=1)
       -> (if testgen supported) v4l2_ctrl_handler_setup(&csid->ctrls)
       -> if (!testgen.enabled && sink无远端) return -ENOLINK
       -> if (csid->phy.need_vc_update)
            -> csid->res->hw_ops->configure_stream(csid, 1)
            -> csid->phy.need_vc_update = false
       -> return 0

STREAMOFF/断电时序

cpp 复制代码
Userspace
  -> csid_video_ops.s_stream = csid_set_stream(enable=0)
     -> if (csid->phy.need_vc_update)
          -> hw_ops->configure_stream(csid, 0)
          -> need_vc_update = false

Userspace
  -> csid_core_ops.s_power = csid_set_power(on=0)
     -> disable_irq()
     -> camss_disable_clocks()
     -> regulator_bulk_disable()
     -> pm_runtime_put_sync()
     -> parent_dev_ops->put(camss, csid->id)

链路建立时的前置影响 - media-ctl建链

cpp 复制代码
media entity link_setup (csid_link_setup)
  Sink pad enable:
    -> 从远端 csiphy 读取 lane_cfg
    -> csid->phy.csiphy_id / lane_cnt / lane_assign 更新
  Source pad enable/disable:
    -> csid->phy.en_vc 按 source pad 位图更新
    -> csid->phy.need_vc_update = true

中断/复位完成同步

cpp 复制代码
IRQ -> csid->res->hw_ops->isr()
  -> 清中断并在 reset done 时 complete(&csid->reset_complete)

csid_set_power(on=1) 内 reset()
  -> 等待 reset_complete(由 isr 完成)

camss-csid-gen2

camss-csid-gen2中使用#define大量定义了寄存器及相关参数,CSI2_RX、RDI_CFG*、TPG_、IRQ_、RST_*等

对外硬件操作实现如下(与框架对接接口)

cpp 复制代码
/*
 * csid_configure_stream - 配置并启停 CSID 数据流
 * @csid: CSID 设备实例
 * @enable: 1 使能流,0 关闭流
 *
 * 根据当前启用的 VC 位图(csid->phy.en_vc)逐路配置:
 * 1) 可选配置 TestGen;
 * 2) 配置 RDI 通道(DT/VC/解码格式/统计与丢弃参数);
 * 3) 配置 CSI2 RX 接收参数(lane/phy/ecc 等);
 * 4) 控制 RDI halt/resume。
 */
static void csid_configure_stream(struct csid_device *csid, u8 enable);

/*
 * csid_configure_testgen_pattern - 设置测试图案模式
 * @csid: CSID 设备实例
 * @val: 期望的测试图案模式值
 *
 * 校验模式范围有效后更新 csid->testgen.mode。
 * 仅更新模式,不直接触发流启停。
 *
 * Return: 0
 */
static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val);

/*
 * csid_hw_version - 读取并解析 CSID 硬件版本
 * @csid: CSID 设备实例
 *
 * 从版本寄存器读取 generation/revision/stepping 并打印调试信息。
 *
 * Return: 原始硬件版本寄存器值
 */
static u32 csid_hw_version(struct csid_device *csid);

/*
 * csid_isr - CSID 中断服务函数
 * @irq: 中断号
 * @dev: 私有数据(struct csid_device *)
 *
 * 处理 TOP/CSI2_RX/各 RDI 的中断状态并清除;
 * 若检测到 reset done,则 complete(reset_complete) 唤醒等待复位流程。
 *
 * Return: IRQ_HANDLED
 */
static irqreturn_t csid_isr(int irq, void *dev);

/*
 * csid_reset - 触发 CSID 软复位并等待完成
 * @csid: CSID 设备实例
 *
 * 清/开复位相关中断,写入 reset strobe,等待 reset_complete 完成信号。
 *
 * Return: 0 成功;-EIO 超时失败
 */
static int csid_reset(struct csid_device *csid);

/*
 * csid_src_pad_code - 根据 sink 格式选择可用 src 格式
 * @csid: CSID 设备实例
 * @sink_code: sink pad 输入格式 code
 * @match_format_idx: 期望匹配索引(与 @match_code 二选一)
 * @match_code: 期望匹配格式 code(与 @match_format_idx 二选一)
 *
 * 对特定 10-bit 输入(如 SBGGR10/Y10)支持原格式或 2x8 打包输出;
 * 其他格式默认透传 sink_code(当索引非法时返回 0)。
 *
 * Return: 选中的 src code;失败返回 0
 */
static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
                 unsigned int match_format_idx, u32 match_code);

/*
 * csid_subdev_init - 按 gen2 硬件初始化子设备能力
 * @csid: CSID 设备实例
 *
 * 初始化 TestGen 模式表与 gen2 支持的模式数量。
 */
static void csid_subdev_init(struct csid_device *csid);

// 导出入口,将上述函数绑定成统一硬件接口
const struct csid_hw_ops csid_ops_gen2 = {
	.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,
};

私有功能模块

cpp 复制代码
// 配置 CSI2 接收器(lane 数、lane mapping、PHY id、ECC/VC mode 等)
static void __csid_configure_rx(struct csid_device *csid,
				struct csid_phy_config *phy, int vc);

// 控制 RDI halt/resume
static void __csid_ctrl_rdi(struct csid_device *csid, int enable, u8 rdi)

// 配置并使能/关闭 test pattern generator
static void __csid_configure_testgen(struct csid_device *csid, u8 enable, u8 vc)

// 配置每个 RDI 通道的协议参数(DT/VC/DT_ID/decode)和 drop/subsample 等
static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 vc)

camss-csid-gen2如何与camss-csid对接?

camss-csid不直接写硬件寄存器,是通过csid->res->hw_ops->xxx()进行调用

平台资源(在camss.c的资源表中)把csid_ops_gen2填进csid_subdev_resources.hw_ops,msm_csid_subdev_init()时赋给csid->res

调用链

cpp 复制代码
上电:csid_set_power -> hw_ops->reset 、hw_ops -> hw_version()
开关流:csid_set_stream() → hw_ops->configure_stream(csid, enable)
testpattern控制:csid_set_test_pattern() → hw_ops->configure_testgen_pattern()
格式传播:csid_try_format/csid_enum_mbus_code → hw_ops->src_pad_code()
初始化:msm_csid_subdev_init() → hw_ops->subdev_init()
中断配置:devm_request_irq(..., csid->res->hw_ops->isr, ...)

camss-csid-4-7

camss-csid-gen2和camss-csid-4-7都实现了同一套struct csid_hw_ops,由camss-csid.c通过res->hw_ops调用

camss-csid-4-7属于较早的寄存器模型相比mss-csid-gen2配置更简单,两者代码框架一致

总结

camss-csid是通用框架层,关键v4l2,媒体拓扑,电源时钟,状态机,格式协商等

camss-csid-gen2是硬件实现层,实现gen2/lite差异寄存器,RDI/TPG/RX/IRQ/reset细节

两者通过csid_hw_ops链接在一起

相关推荐
程序员JerrySUN2 小时前
Jetson边缘嵌入式实战课程第五讲:Jetson Secure Boot - 安全启动
android·linux·服务器·人工智能·安全·unity·游戏引擎
穷人小水滴3 小时前
ssh-bridge: 在 Linux 虚拟机中转发消息的简单实现 (UNIX socket)
linux·ssh·unix
齐齐大魔王3 小时前
Linux-网络抓包
linux·运维·网络
JP-Destiny3 小时前
Linux-配置Ubuntu的IP
linux·tcp/ip·ubuntu
ofoxcoding3 小时前
Codex 官网访问 + 完整安装教程:macOS / Windows / Linux 一次跑通(2026)
linux·windows·macos·ai
magic_now3 小时前
systemctl stop 会杀死子进程吗?
linux
sulikey3 小时前
如何在Ubuntu中判断是否已安装ncurses库
linux·运维·ubuntu·ncurses
Cat_Rocky3 小时前
Linux学习-ansible自动化
linux·学习·ansible
programhelp_3 小时前
Ramp OA 四关全过,CodeSignal OOD 完整复盘
linux·前端·python