Linux PXA2xx/PXA3xx MFP(多功能引脚)配置深度指南:从板级 pin_config 到 MFPR 寄存器实现
【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux
导读
本文以 Linux 内核官方文档《MFP Configuration for PXA2xx/PXA3xx Processors》为主体,结合当前 Linux 内核源码树中 Marvell PXA 平台的真实实现,系统讲解 MFP(Multi-Function Pin,多功能引脚)机制的架构设计、API 用法与寄存器原理。你将掌握:PXA3xx 与 PXA25x/PXA27x 在引脚复用上的本质差异、如何为一块新的 PXA 开发板编写pin_config配置数组、32 位 MFP 配置值的每一位如何编码,以及这些配置最终如何被转换为 MFPR(PXA3xx)或 GAFRx/GPDRx/PGSR 等(PXA2xx)寄存器操作。
MFP 基本概念:从 GPIO 复用走向独立引脚管理
MFP 是 Marvell PXA3xx 及后续 PXA 系列处理器引入的引脚复用(pin-mux)逻辑。与 PXA25x/PXA27x 直接在 GPIO 控制器内部完成 alternate function 设置不同,从 PXA3xx 开始,引脚复用功能被完全从 GPIO 控制器中剥离出来,交由独立的 MFP 逻辑承担。除了引脚复用,MFP 还统一控制每个引脚的低功耗状态(low power state)、驱动强度(driving strength)、上下拉电阻(pull-up/down)以及事件检测(event detection)。
文档给出了 MFP 逻辑与 SoC 内部各外设之间的连接关系示意图:
+--------+ | |--(GPIO19)--+ | GPIO | | | |--(GPIO...) | +--------+ | | +---------+ +--------+ +------>| | | PWM2 |--(PWM_OUT)-------->| MFP | +--------+ +------>| |-------> to external PAD | +---->| | +--------+ | | +-->| | | SSP2 |---(TXD)----+ | | +---------+ +--------+ | | | | +--------+ | | | Keypad |--(MKOUT4)----+ | +--------+ | | +--------+ | | UART2 |---(TXD)--------+ +--------+从图中可以看到,GPIO 控制器、PWM2、SSP2、Keypad、UART2 等内部控制器发出的信号,可以经 MFP 逻辑汇聚后路由到外部 PAD(引脚焊球)。需要注意:外部 PAD 的命名(如MFP_PIN_GPIO19)并不表示该引脚专属于 GPIO19,而只是提示"在芯片内部,这个引脚可以从 GPIO 控制器的 GPIO19 信号路由而来"。
在 include/linux/soc/pxa/mfp.h 中,所有可配置引脚被定义为一个枚举常量表:从MFP_PIN_GPIO0到MFP_PIN_GPIO127,再到MFP_PIN_GPIO128~MFP_PIN_GPIO191、MFP_PIN_GPIO255,以及MFP_PIN_GPIO0_2~MFP_PIN_GPIO17_2这样的"第二路由"引脚、MFP_PIN_ULPI_STP、MFP_PIN_DF_*(NAND Flash 接口)、MFP_PIN_MMC1_*、PXA930 专有引脚(MFP_PIN_GSIM_UIO等)和 MMP2 专有引脚(MFP_PIN_TWSI1_SCL等),最终以MFP_PIN_MAX结尾。其中mfp_to_gpio(m) ((m) % 256)宏(mfp.h)负责从 MFP 引脚编号反查对应的 GPIO 编号。
PXA3xx 与 PXA2xx 的关键差异:MFP/GPIO 职责分离
文档明确指出,从 PXA25x/PXA27x 的 GPIO alternate function 机制演进到新的 MFP 机制,有四个核心变化:
GPIO 控制器成为纯粹的外设控制器:PXA3xx 上的 GPIO 控制器与 PWM、SSP、UART 一样,是一个独立控制器,内部有 128 路信号,可通过一个或多个 MFP 路由到外部。例如
GPIO<0>既可以经MFP_PIN_GPIO0路由,也可以经MFP_PIN_GPIO0_2路由(见 arch/arm/mach-pxa/mfp-pxa300.h)。GPIO 控制器不再承载复用功能:alternate function 配置被移除后,GPIO 控制器只剩下纯 GPIO 功能——信号电平控制、方向控制、电平变化检测。
引脚低功耗状态由 MFP 控制:PXA2xx 上承担此职责的
PGSRx寄存器在 PXA3xx 上已无用武之地。唤醒检测由 MFP 控制:
PWER不再控制 GPIO 的唤醒,根据睡眠状态的不同,由ADxER寄存器(定义于pxa3xx-regs.h)控制来自 MFP 的唤醒。
因此文档建议在表述上严格区分:说GPIO<xx>指代一个 GPIO 信号,说MFP<xxx>或 "pin xxx" 则指代一个物理焊盘/焊球。
MFP API 使用指南:如何为开发板编写引脚配置
对于板级(board)代码编写者,文档给出了完整的操作路径,这也是 MFP API 最核心的实战场景。
第一步:选择正确的头文件
在你的<board>.c文件中,根据使用的处理器只包含一个对应头文件:
mfp-pxa25x.hmfp-pxa27x.hmfp-pxa300.hmfp-pxa320.hmfp-pxa930.h
严禁同时包含多个——不同处理器的引脚配置定义可能互相冲突(同名宏在不同处理器上含义和设置不同)。例如支持 PXA300/PXA310 与 PXA320 两种组合的 zylonite 平台,就拆分为zylonite_pxa300.c和zylonite_pxa320.c两个文件分别处理。另外,PXA300 与 PXA310 的引脚配置几乎一致(PXA310 仅多支持少量引脚),因此差异统一涵盖在单个mfp-pxa300.h中。
第二步:准备初始引脚配置数组
板级代码通常声明一个__initdata的unsigned long数组:
static unsigned long mainstone_pin_config[] __initdata = { /* Chip Select */ GPIO15_nCS_1, /* LCD - 16bpp Active TFT */ GPIOxx_TFT_LCD_16BPP, GPIO16_PWM0_OUT, /* Backlight */ /* MMC */ GPIO32_MMC_CLK, GPIO112_MMC_CMD, GPIO92_MMC_DAT_0, GPIO109_MMC_DAT_1, GPIO110_MMC_DAT_2, GPIO111_MMC_DAT_3, ... /* GPIO */ GPIO1_GPIO | WAKEUP_ON_EDGE_BOTH, };文档对这一写法给出了三点实践建议:
- a) 使用
__initdata:配置数组经pxa{2xx,3xx}_mfp_config()写入实际寄存器后即为一次性数据,标记__initdata可在内核初始化后释放,节省内存。 - b) 善用简化定义:当一个组件只存在唯一可能的引脚配置时(如 PXA25x/PXA27x 上的
GPIOxx_TFT_LCD_16BPP),可直接使用简化宏。 - c) 唤醒能力用
OR叠加:若某引脚在板级设计上可以从低功耗状态唤醒系统,可将其与下列任一宏按位或:WAKEUP_ON_EDGE_BOTHWAKEUP_ON_EDGE_RISEWAKEUP_ON_EDGE_FALLWAKEUP_ON_LEVEL_HIGH—— 专门用于使能 keypad GPIO 的唤醒
这些宏的定义可以在 arch/arm/mach-pxa/mfp-pxa2xx.h 中找到,它们实际是MFP_LPM_CAN_WAKEUP与MFP_LPM_EDGE_*的组合。
- d) 唤醒的真正生效条件:虽然在配置中标注了唤醒能力,但这不意味着引脚一定会唤醒系统。只有当内核调用
set_irq_wake()(传入GPIO_IRQ(xx)或gpio_to_irq()得到的 GPIO IRQ),并最终调用gpio_set_wake()完成实际寄存器设置后,唤醒才会生效。对 PXA3xx 而言,内部逻辑只有在ADxER寄存器中相应位被置位时才唤醒系统,而这些位可以很好地映射到对应外设,因此也可以对外设 IRQ调用set_irq_wake()来使能唤醒。
真实板级案例
当前仓库中保留了多个符合上述模式的板级示例,例如 spitz.c 的spitz_pin_config[]、gumstix.c 的gumstix_pin_config[]、am200epd.c 与 am300epd.c 的*_pin_config[],均以static unsigned long ... __initdata形式声明,随后调用pxa{2xx,3xx}_mfp_config(pin_config, ARRAY_SIZE(pin_config))使其生效。
PXA3xx 上的 MFPR 寄存器详解
PXA3xx 上每个外部 I/O 焊盘(除特殊用途外)都关联一份 MFP 逻辑,并由一个 MFP 寄存器(MFPR)控制。MFPR 基地址为0x40e10000(见 arch/arm/mach-pxa/mfp-pxa3xx.h 的MFPR_BASE定义)。
MFPR 的位定义(适用于 PXA300/PXA310/PXA320):
31 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +-------------------------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | RESERVED |PS|PU|PD| DRIVE |SS|SD|SO|EC|EF|ER|--| AF_SEL | +-------------------------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+| 位 | 名称 | 含义 |
|---|---|---|
| Bit 0-2 | AF_SEL | 复用功能选择,8 种可能(0-7) |
| Bit 3 | RESERVED | 保留 |
| Bit 4 | EDGE_RISE_EN | 使能该引脚上升沿检测 |
| Bit 5 | EDGE_FALL_EN | 使能该引脚下降沿检测 |
| Bit 6 | EDGE_CLEAR | 禁用该引脚边沿检测 |
| Bit 7 | SLEEP_OE_N | 低功耗模式下使能输出 |
| Bit 8 | SLEEP_DATA | 低功耗模式下引脚输出的数据 |
| Bit 9 | SLEEP_SEL | 低功耗模式信号的选择控制 |
| Bit 10-12 | DRIVE | 驱动强度与压摆率(见下表) |
| Bit 13 | PULLDOWN_EN | 使能该引脚内部下拉电阻 |
| Bit 14 | PULLUP_EN | 使能该引脚内部上拉电阻 |
| Bit 15 | PULL_SEL | 上拉/下拉状态由所选复用功能控制(0),或由PULL{UP,DOWN}_EN位控制(1) |
DRIVE字段(Bit 10-12)的编码如下:
| 值 | 驱动能力 |
|---|---|
| 0b000 | fast 1mA |
| 0b001 | fast 2mA |
| 0b010 | fast 3mA |
| 0b011 | fast 4mA |
| 0b100 | slow 6mA |
| 0b101 | fast 6mA |
| 0b110 | slow 10mA |
| 0b111 | fast 10mA |
在 mfp-pxa300.h 中可以看到与这些位域对应的具体宏应用,例如 QCI 摄像头接口的数据线使用MFP_CFG_DRV(GPIO39, AF1, DS04X)指定 4mA 驱动,I2C 引脚使用MFP_CFG_LPM(GPIO21, AF1, PULL_HIGH)在低功耗模式下保持上拉,Keypad 输入GPIO3_KP_DKIN_6等则使用MFP_CFG_LPM(..., FLOAT)在低功耗模式下浮空。
统一 MFP 设计:一套 API 覆盖两代处理器
由于 PXA2xx 与 PXA3xx 的引脚复用处理方式不同,内核引入了一套统一 MFP API:先为所有可能的引脚配置定义出与处理器、平台无关的通用定义,再由实际 API 将这些定义转换为对应处理器的寄存器设置并使其生效。
涉及的源文件
| 文件 | 职责 |
|---|---|
| arch/arm/mach-pxa/mfp.h | 统一引脚定义(可配置引脚的枚举常量)与处理器无关的位定义(实际内容在 include/linux/soc/pxa/mfp.h) |
| arch/arm/mach-pxa/mfp-pxa3xx.h | PXA3xx 专用 MFPR 寄存器位定义与 PXA3xx 公共引脚配置 |
| arch/arm/mach-pxa/mfp-pxa2xx.h | PXA2xx 专用定义与 PXA25x/PXA27x 公共引脚配置 |
| arch/arm/mach-pxa/mfp-pxa25x.h、mfp-pxa27x.h、mfp-pxa300.h、mfp-pxa320.h、mfp-pxa930.h | 各处理器专用定义 |
| arch/arm/mach-pxa/mfp-pxa3xx.c、mfp-pxa2xx.c | 引脚配置在具体处理器上的落地实现 |
32 位 MFP 配置值的位域编码
一个 MFP 配置用一个 32 位整数表示(以下注释直接来自 include/linux/soc/pxa/mfp.h):
- bit 0..9 —— MFP 引脚号(最多 1024 个引脚)
- bit 10..12 —— 复用功能选择(Alternate Function Selection)
- bit 13..15 —— 驱动强度(Drive Strength)
- bit 16..18 —— 低功耗模式状态(Low Power Mode State)
- bit 19..20 —— 低功耗模式边沿检测(Low Power Mode Edge Detection)
- bit 21..22 —— 运行模式上拉/下拉状态(Run Mode Pull State)
为便于定义,内核提供了一系列构造宏(同样定义于 include/linux/soc/pxa/mfp.h):
| 宏 | 用途 |
|---|---|
MFP_CFG_DEFAULT | 默认配置:复用功能 0、驱动强度 fast 3mA(MFP_DS03X)、低功耗模式默认、无边沿检测、无上拉/下拉 |
MFP_CFG(pin, af) | 默认 MFPR 值 + 复用功能 |
MFP_CFG_DRV(pin, af, drv) | 默认 MFPR 值 + 复用功能 + 驱动强度 |
MFP_CFG_LPM(pin, af, lpm) | 默认 MFPR 值 + 复用功能 + 低功耗模式 |
MFP_CFG_X(pin, af, drv, lpm) | 默认 MFPR 值 + 复用功能 + 驱动强度 + 低功耗模式 |
配套的字段取值宏包括:复用功能MFP_AF0~MFP_AF7;驱动强度MFP_DS01X~MFP_DS13X(对应 1mA~13mA 档位);低功耗状态MFP_LPM_DEFAULT、MFP_LPM_DRIVE_LOW、MFP_LPM_DRIVE_HIGH、MFP_LPM_PULL_LOW、MFP_LPM_PULL_HIGH、MFP_LPM_FLOAT、MFP_LPM_INPUT;边沿检测MFP_LPM_EDGE_NONE/RISE/FALL/BOTH;运行态上下拉MFP_PULL_NONE/LOW/HIGH/BOTH/FLOAT。
一个典型配置宏示例:
#define GPIO94_SSP3_RXD MFP_CFG_X(GPIO94, AF1, DS08X, FLOAT)其含义为:GPIO94 可配置为 SSP3_RXD,复用功能选择为 1(AF1),驱动强度为 0b101(fast 6mA,即MFP_DS08X),低功耗模式下引脚浮空(FLOAT)。文档特别提醒:这是该引脚作为 SSP3_RXD 的默认设置,板级代码可以微调,但通常不建议——因为这些默认值经过精心编码,在大多数场景下都能正常工作。
在 PXA2xx 侧,mfp-pxa2xx.h 复用了 mfp.h 中的大部分位定义(MFP_PIN(x)、MFP_AFx、MFP_LPM_DRIVE_{LOW,HIGH}、MFP_LPM_EDGE_x),并额外增加两个 PXA2xx 专用位:
- bit 23 —— 输入/输出方向(
MFP_DIR_IN/MFP_DIR_OUT) - bit 24 —— 唤醒使能(
MFP_LPM_CAN_WAKEUP) - bit 25 —— 保持输出(
MFP_LPM_KEEP_OUTPUT,用于低功耗模式下需要保持最后输出电平的引脚)
并相应提供MFP_CFG_IN(pin, af)与MFP_CFG_OUT(pin, af, state)两个方向专用宏。注意:配置为输出的引脚必须提供低功耗状态,且该状态应有助于最小化功耗。
寄存器设置转换:PXA3xx 直接映射,PXA2xx 多寄存器协同
PXA3xx的转换非常直接:大部分位可以轻松转换为 MFPR 值。实现中会计算两套 MFPR 值——运行态(run-time)一套、低功耗模式一套,以允许两者设置不同。从源码看,mfp.h 暴露了底层接口:mfp_read()/mfp_write()直接读写 MFPR 寄存器,mfp_config()批量配置一组 MFPR,mfp_config_lpm()在挂起(suspend)时应用低功耗 MFPR 配置,mfp_config_run()在恢复(resume)后恢复运行态配置;处理器专用代码通过mfp_init_base()和mfp_init_addr()(配合MFP_ADDR_X/MFP_ADDR/MFP_ADDR_END地址映射表)初始化各引脚的 MFPR 偏移。此外 mfp-pxa3xx.h 将mfp_read/mfp_write/mfp_config封装为pxa3xx_mfp_read/pxa3xx_mfp_write/pxa3xx_mfp_config内联函数,并注明不推荐直接使用前两者。挂起/恢复的具体流程可在 arch/arm/mach-pxa/mfp-pxa3xx.c 中看到:pxa3xx_mfp_suspend调用mfp_config_lpm(),pxa3xx_mfp_resume调用mfp_config_run()并清除ASCR中的 RDH/D1S/D2S/D3S 位。
PXA2xx的转换则复杂得多,涉及大量寄存器协同操作,包括GAFRx(复用功能)、GPDRx(方向)、PGSRx(低功耗状态)、PWER(唤醒使能)、PKWR(键盘唤醒)、PFER(下降沿使能)和PRER(上升沿使能),具体转换逻辑见 arch/arm/mach-pxa/mfp-pxa2xx.c。以pxa2xx_mfp_config()(mfp-pxa2xx.c)为例,它逐项校验引脚合法性(__mfp_validate,通过gpio_desc表确认该 GPIO 有效)后,关中断调用__mfp_config_gpio()完成 GAFR/GPDR/PGSR 的设置;gpio_set_wake()(mfp-pxa2xx.c)则负责 PWER/PKWR/PRER/PFER 的唤醒位操作,并通过mux_mask处理 PXA27x 上 PWER 复用的 GPIO 位(如PWER_WEMUX2_GPIO38、PWER_WEMUX3_GPIO31等)。pxa2xx_mfp_suspend/pxa2xx_mfp_resume还会保存并在恢复时还原 GAFR/GPDR/GPLR/PGSR 四组寄存器(mfp-pxa2xx.c),并考虑MFP_LPM_KEEP_OUTPUT对输出电平的保持。
总结:一套配置定义,两代架构落地
MFP 机制是 PXA 系列处理器引脚管理的关键抽象:在概念层,它以"信号(GPIO/外设信号)— MFP 逻辑 — 物理引脚"三者的清晰分离取代了旧式 GPIO alternate function;在板级实践层,开发者只需按处理器选择唯一头文件、填写__initdata的pin_config数组并按需叠加唤醒宏,再交给pxa{2xx,3xx}_mfp_config();在实现层,同一套 32 位配置编码既可近乎一比一映射到 PXA3xx 的 MFPR 寄存器(含两套运行/低功耗值),也能被翻译为 PXA2xx 的 GAFRx/GPDRx/PGSRx/PWER/PKWR/PFER/PRER 多寄存器操作,并借助 syscore_ops 完成挂起/恢复时的状态保存与还原。理解这条从文档定义到 include/linux/soc/pxa/mfp.h 位域宏、再到 mfp-pxa3xx.c 与 mfp-pxa2xx.c 落地实现的主线,即可为任意 PXA 平台快速完成可靠、低功耗友好的引脚配置。
【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考