1.概要
目的:确认两个结构体的关系。
rockchip_pin_group谁对引脚的定义。
rockchip_pmx_func是对功能的定义,一个功能有一组引脚共同构成。
2.内容
在瑞芯微RK3588的pinctrl驱动中,struct rockchip_pin_group
和 struct rockchip_pmx_func
是核心数据结构,用于描述引脚复用(Pinmux)和功能配置。以下是它们的详细解析:
1. struct rockchip_pin_group
作用:
表示一组物理引脚的集合,通常对应某个外设功能(如SPI、I2C)的引脚配置。
关键成员:
struct rockchip_pin_group {
const char *name; // 引脚组名称(如 "spi0_sck")
const unsigned int *pins; // 引脚编号数组(如 GPIO0_A0, GPIO0_A1)
const unsigned int num_pins; // 引脚数量
const unsigned int *funcs; // 每个引脚对应的复用功能索引
const unsigned int *drive; // 驱动强度配置(可选)
const unsigned int *pull; // 上拉/下拉配置(可选)
const unsigned int *schmitt; // 施密特触发器配置(可选)
};
示例:
定义SPI0的SCK引脚组:
static const unsigned int spi0_sck_pins[] = { RK_PD0 };
static const unsigned int spi0_sck_funcs[] = { RK_FUNC_SPI0 };
struct rockchip_pin_group spi0_sck_group = {
.name = "spi0_sck",
.pins = spi0_sck_pins,
.num_pins = ARRAY_SIZE(spi0_sck_pins),
.funcs = spi0_sck_funcs,
};
2. struct rockchip_pmx_func
作用:
描述一个逻辑功能(如SPI0),包含该功能所需的引脚组及配置。
关键成员:
struct rockchip_pmx_func {
const char *name; // 功能名称(如 "spi0")
const char * const *groups; // 关联的引脚组数组(如 "spi0_sck", "spi0_mosi")
const unsigned int num_groups; // 引脚组数量
const unsigned int *ctrl; // 额外控制配置(如时钟使能)
};
示例:
定义SPI0功能:
static const char * const spi0_groups[] = {
"spi0_sck",
"spi0_mosi",
"spi0_miso",
"spi0_cs0",
};
struct rockchip_pmx_func spi0_func = {
.name = "spi0",
.groups = spi0_groups,
.num_groups = ARRAY_SIZE(spi0_groups),
};
3. 两者关系
-
功能与引脚组的绑定:
一个功能(pmx_func
)由多个引脚组(pin_group
)组成。例如,SPI0功能需要SCK、MOSI、MISO、CS等引脚组。 -
配置流程:
- 在设备树(DTS)中定义引脚组和功能:
pinctrl_spi0: spi0@0 { rockchip,pins = < RK_PD0 RK_FUNC_SPI0 &pcfg_pull_none, RK_PD1 RK_FUNC_SPI0 &pcfg_pull_none, /* ... */ >; rockchip,function = "spi0"; };
- 驱动解析DTS,填充
rockchip_pin_group
和rockchip_pmx_func
结构体。 - 当外设(如SPI控制器)请求
pinctrl_select_state()
时,系统根据功能名称找到对应的pmx_func
,并配置所有关联的pin_group
。
- 在设备树(DTS)中定义引脚组和功能:
4. 高级配置
-
电气参数:
通过drive
、pull
、schmitt
等成员可配置引脚的驱动强度、上拉/下拉电阻、施密特触发器等。 -
动态切换:
支持运行时切换功能(如从UART切换到GPIO),通过pinctrl_lookup_state()
和pinctrl_select_state()
实现。
5. 调试建议
-
检查DTS配置:
确保引脚组和功能名称与驱动代码一致。 -
查看pinctrl日志:
启用CONFIG_DEBUG_PINCTRL
,通过dmesg
查看引脚配置过程。 -
硬件手册:
参考《RK3588 TRM》的GPIO和Pinmux章节,确认引脚复用编号和电气参数。
通过这两个结构体,RK3588的pinctrl驱动实现了灵活的引脚复用管理,支持外设动态配置和硬件抽象。
3.关联链接
4.关联知识
1.解析设备树
pinctrl_spi0: spi0@0 {
rockchip,pins = <
RK_PD0 RK_FUNC_SPI0 &pcfg_pull_none,
RK_PD1 RK_FUNC_SPI0 &pcfg_pull_none,
/* ... */
>;
rockchip,function = "spi0";
};
在瑞芯微RK3588的pinctrl驱动中,解析用户提供的设备树节点 pinctrl_spi0
后,生成的 struct rockchip_pin_group
和 struct rockchip_pmx_func
结构体如下:
1. struct rockchip_pin_group
解析
设备树中的 rockchip,pins
数组每个条目对应一个引脚组。假设条目为:
rockchip,pins = <
RK_PD0 RK_FUNC_SPI0 &pcfg_pull_none,
RK_PD1 RK_FUNC_SPI0 &pcfg_pull_none,
RK_PD2 RK_FUNC_SPI0 &pcfg_pull_none,
RK_PD3 RK_FUNC_SPI0 &pcfg_pull_none
>;
生成的引脚组:
每个条目生成一个 rockchip_pin_group
,名称自动生成(如 spi0_pd0
, spi0_pd1
等):
/* 引脚组 1: PD0 */
static const unsigned int spi0_pd0_pins[] = { RK_PD0 };
static const unsigned int spi0_pd0_funcs[] = { RK_FUNC_SPI0 };
static const unsigned int spi0_pd0_pull[] = { PULL_NONE };
struct rockchip_pin_group spi0_pd0_group = {
.name = "spi0_pd0",
.pins = spi0_pd0_pins,
.num_pins = 1,
.funcs = spi0_pd0_funcs,
.pull = spi0_pd0_pull,
};
/* 引脚组 2: PD1 */
static const unsigned int spi0_pd1_pins[] = { RK_PD1 };
static const unsigned int spi0_pd1_funcs[] = { RK_FUNC_SPI0 };
static const unsigned int spi0_pd1_pull[] = { PULL_NONE };
struct rockchip_pin_group spi0_pd1_group = {
.name = "spi0_pd1",
.pins = spi0_pd1_pins,
.num_pins = 1,
.funcs = spi0_pd1_funcs,
.pull = spi0_pd1_pull,
};
/* 后续引脚组(PD2, PD3)结构类似,名称依次为 spi0_pd2, spi0_pd3 */
2. struct rockchip_pmx_func
解析
设备树中的 rockchip,function = "spi0"
关联到功能名称,生成的 pmx_func
结构体如下:
/* 定义所有引脚组名称 */
static const char * const spi0_groups[] = {
"spi0_pd0", /* 对应 PD0 */
"spi0_pd1", /* 对应 PD1 */
"spi0_pd2", /* 对应 PD2 */
"spi0_pd3", /* 对应 PD3 */
};
/* 生成功能结构体 */
struct rockchip_pmx_func spi0_func = {
.name = "spi0",
.groups = spi0_groups,
.num_groups = ARRAY_SIZE(spi0_groups),
};
3. 关键解析逻辑
- 引脚组生成:
- 每个
rockchip,pins
条目生成一个rockchip_pin_group
。 - 组名自动生成(如
功能名_引脚名
,如spi0_pd0
)。 - 引脚编号、功能、电气参数(如上拉)从设备树解析。
- 每个
- 功能关联:
rockchip,function
属性匹配pmx_func
的name
。- 所有关联的引脚组名称存入
pmx_func.groups
数组。
4. 实际应用场景
当外设(如SPI控制器)请求配置 pinctrl_spi0
状态时:
- 驱动通过
rockchip,function = "spi0"
找到spi0_func
。 - 遍历
spi0_func.groups
中的所有引脚组(如spi0_pd0
,spi0_pd1
)。 - 对每个引脚组调用
pinctrl_set_mux()
和pinctrl_set_bias()
,完成引脚复用和电气配置。
5. 验证方法
-
查看DTS映射:
确保设备树中的引脚编号(如RK_PD0
)和功能(RK_FUNC_SPI0
)与硬件手册一致。 -
调试日志:
启用CONFIG_DEBUG_PINCTRL
,通过dmesg
观察引脚配置过程,例如:pinctrl: group spi0_pd0 set to func SPI0 pinctrl: group spi0_pd1 set to func SPI0
-
代码检查:
在驱动源码中搜索spi0_func
和spi0_pd0_group
,确认结构体定义与解析逻辑一致。
通过这种方式,RK3588的pinctrl驱动实现了引脚复用的灵活配置,支持外设动态切换功能(如从UART切换到SPI)。
6.关系分析
2.rockchip,pins中的rockchip和pins是表示两个东西,还是一个东西就叫rockchip,pins
在设备树(DTS)语法中,rockchip,pins
是一个复合属性名,由两部分组成:
rockchip
:厂商前缀(Vendor Prefix),表示这是瑞芯微(Rockchip)自定义的属性。pins
:属性名称(Property Name),表示该属性用于描述引脚(Pin)配置。
具体解析
-
语法规则:
设备树属性名通常采用厂商前缀, 属性名
的格式(如rockchip,function
、fsl,pinctrl
),目的是避免不同厂商的属性命名冲突。 -
rockchip,pins
的作用:
该属性定义了一组引脚的复用(Pinmux)和电气配置(如上拉/下拉、驱动强度等)。每个条目(Entry)的格式为:<引脚编号> <功能选择> <电气配置1> <电气配置2> ...
示例解析
以您的代码为例:
rockchip,pins = <
RK_PD0 RK_FUNC_SPI0 &pcfg_pull_none,
RK_PD1 RK_FUNC_SPI0 &pcfg_pull_none,
RK_PD2 RK_FUNC_SPI0 &pcfg_pull_none,
RK_PD3 RK_FUNC_SPI0 &pcfg_pull_none
>;
每个条目的含义:
-
RK_PD0
:
引脚编号(Pin Number),表示物理引脚(如 GPIO0 的第 0 号引脚)。 -
RK_FUNC_SPI0
:
功能选择(Function Select),表示将引脚配置为 SPI0 的某个信号(如 SCK、MOSI 等)。 -
&pcfg_pull_none
:
电气配置(Electrical Configuration),此处表示禁用上拉/下拉电阻(Pull-Up/Pull-Down)。
驱动解析逻辑
在瑞芯微的 pinctrl 驱动中,rockchip,pins
属性会被解析为:
-
引脚组(
struct rockchip_pin_group
):
每个条目生成一个引脚组,包含引脚编号、功能选择和电气配置。 -
功能(
struct rockchip_pmx_func
):
所有引脚组通过rockchip,function
属性关联到一个逻辑功能(如"spi0"
)。
总结
rockchip,pins
是一个整体属性名,由厂商前缀rockchip
和属性名pins
组成。- 每个条目定义了一个引脚的复用和电气配置,驱动会将其解析为
rockchip_pin_group
结构体。 - 所有引脚组通过
rockchip,function
属性绑定到一个逻辑功能(如"spi0"
),生成rockchip_pmx_func
结构体。
3.rockchip_pmx_func中的groups和rockchip_pin_group是什么关系
在瑞芯微RK3588的pinctrl驱动中,struct rockchip_pmx_func
的 groups
成员与 struct rockchip_pin_group
的关系是功能与引脚组的绑定关系,具体如下:
1. 核心关系
rockchip_pmx_func.groups
是一个字符串数组,存储了该功能(如SPI0)依赖的所有引脚组的名称(如"spi0_sck"
,"spi0_mosi"
)。rockchip_pin_group
是具体的引脚配置实例,每个实例对应一个物理引脚或一组引脚的复用和电气参数。
驱动通过 groups
中的名称找到对应的 rockchip_pin_group
实例,完成功能配置。
2. 示例解析
假设设备树中定义了一个SPI0功能:
pinctrl_spi0: spi0@0 {
rockchip,pins = <
RK_PD0 RK_FUNC_SPI0 &pcfg_pull_none, /* 引脚组1: SCK */
RK_PD1 RK_FUNC_SPI0 &pcfg_pull_none, /* 引脚组2: MOSI */
RK_PD2 RK_FUNC_SPI0 &pcfg_pull_none, /* 引脚组3: MISO */
RK_PD3 RK_FUNC_SPI0 &pcfg_pull_none /* 引脚组4: CS0 */
>;
rockchip,function = "spi0";
};
生成的 rockchip_pmx_func
:
/* 定义所有引脚组名称 */
static const char * const spi0_groups[] = {
"spi0_sck", /* 对应 SCK 引脚组 */
"spi0_mosi", /* 对应 MOSI 引脚组 */
"spi0_miso", /* 对应 MISO 引脚组 */
"spi0_cs0", /* 对应 CS0 引脚组 */
};
/* 生成功能结构体 */
struct rockchip_pmx_func spi0_func = {
.name = "spi0",
.groups = spi0_groups, /* 绑定引脚组名称 */
.num_groups = ARRAY_SIZE(spi0_groups),
};
生成的 rockchip_pin_group
示例(以SCK为例):
struct rockchip_pin_group spi0_sck_group = {
.name = "spi0_sck", /* 与 groups 中的名称匹配 */
.pins = &rk_pd0, /* 物理引脚 PD0 */
.funcs = &rk_func_spi0, /* 复用功能 SPI0 */
.pull = &pull_none, /* 电气配置:无上拉 */
};
3. 配置流程
当外设(如SPI控制器)请求配置 pinctrl_spi0
状态时:
- 驱动通过
rockchip,function = "spi0"
找到spi0_func
。 - 遍历
spi0_func.groups
中的每个引脚组名称(如"spi0_sck"
)。 - 根据名称找到对应的
rockchip_pin_group
实例(如spi0_sck_group
)。 - 对每个引脚组调用底层函数(如
rockchip_pin_config()
),配置引脚复用和电气参数。
4. 设计意义
- 模块化:
将功能(如SPI0)与引脚组解耦,便于复用引脚组配置(如多个功能共享同一引脚组)。 - 可扩展性:
新增功能只需定义新的rockchip_pmx_func
并关联现有引脚组,无需修改底层驱动。 - 动态配置:
支持运行时切换功能(如从UART切换到GPIO),通过替换groups
数组实现。
5. 验证方法
-
设备树检查:
确保rockchip,function
名称与rockchip_pmx_func.name
一致,且rockchip,pins
条目生成的引脚组名称存在于groups
数组中。 -
驱动调试:
启用CONFIG_DEBUG_PINCTRL
,观察日志中引脚组和功能的绑定关系:pinctrl: func spi0 requires groups: spi0_sck, spi0_mosi, spi0_miso, spi0_cs0 pinctrl: group spi0_sck configured for func SPI0
通过这种设计,RK3588的pinctrl驱动实现了引脚复用的高度灵活性和可维护性。