【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_data 和 data[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_CTRL10、22..32)

CSIPHY参数表 - 物理层

参数 归属 代码位置 作用
num_data / datai.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_CFG5 (T_HS_DTERM、HS_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链接在一起

相关推荐
小燕子~~6 小时前
Photoshop2026新版 AI 功能实测,看这一篇就够了
图像处理·人工智能·ai·aigc·photoshop
夜听莺儿鸣7 小时前
502-003_Linux 中断与异常(一):从Linux角度理解中断与异常
linux·中断与异常·linux中断
杨云龙UP7 小时前
TDengine 3.4.2.8 Community 三节点三副本生产集群部署实战(DNode/MNode/taosAdapter/Explorer)
大数据·linux·运维·数据库·tdengine·时序库
向成科技8 小时前
XC3576H工控主板|深度适配Ubuntu 26.04 LTS,释放边缘AI与工业开发新潜能
linux·人工智能·ubuntu·机器人·硬件·主板·边缘ai
Fcy6489 小时前
Linux下 进程间关系与守护进程
linux·运维·服务器·守护进程
码农小韩9 小时前
Linux驱动理论(二)——Linux字符设备驱动
linux·嵌入式软件开发·linux操作系统·linux应用开发·linux驱动理论
well06129 小时前
Linux粘滞位与Makefile机制深度解析
linux·运维·服务器
再写一行代码就下班9 小时前
linux sh脚本在windows修改导致无法使用解决方式
java·linux·centos
额额额对了10 小时前
SPI通信
linux·c语言·汇编·单片机·嵌入式硬件·arm
子木HAPPY阳VIP10 小时前
Ubuntu 关闭防火墙操作步骤
linux·运维·ubuntu