框架总览
源码仓库:基于树莓派代码仓库,分析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)
- lane/clock 使能(
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_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链接在一起