高通学习2-QUP(TODO)
1 QUP原理
STM32(以及绝大多数传统 MCU)与高通(以及现代先进应用处理器 SoC)在底层外设的设计哲学上,走的是两条完全不同的进化路线。习惯的 STM32 属于“专职专责”的硬件硬编码架构,而高通 QUPv3 则属于“软硬件可编程的通用流处理架构”。
在 STM32 里面,查数据手册,会清晰地看到 I2C1、SPI1、TIM1(PWM) 都有各自独立的物理基地址、独立的硬件状态机和内部寄存器。意法半导体(ST)在设计芯片时,硅片上这块区域画的就是 I2C 的逻辑门,那块区域画的就是 SPI 的移位寄存器。它们井水不犯河水。
每个外设的寄存器行为在出厂时就死掉了,完全由硬件逻辑控制,几乎没有软件开销,响应极其精准(符合工业控制的死脑筋需求)。
高通的 SoC(尤其是像 AR1+ 这种物理尺寸暴减 26% 的特化芯片)面临的生存环境极为恶劣:寸土寸金的硅片面积、极其复杂的客户外设需求、以及对引脚数量近乎变态的压缩。
于是,高通采用了 QUPv3 (Qualcomm Universal Peripheral) 架构。在 QUPv3 模块内部,每一个所谓的 SE (Serial Engine,串行引擎),本质上是一台微型的、高度优化的硬件流处理器。个 SE 内部没有焊死任何具体的 I2C 或 SPI 逻辑,它只包含通用的数据 FIFO、移位器、时钟分频器和一个可控的状态机控制器。这也是QUP 最小可编程单元,单 SE 同一时间仅支持一种协议(UART/SPI/I2C/I3C),由固件决定协议;SoC 内置两组 QUP 模块,合计16 个 SE(QUP0+QUP1 各 8 路)。

当系统开机启动时(在 TrustZone 或者是音频 DSP 微内核初始化的阶段),系统会向这个 SE 注入一段极小的微代码(Microcode)或协议固件。
同时还有GPI(通用 DMA 引擎)概念。每个 SE 配套独立 GPI,成对生产者 / 消费者 DMA 通道,负责内存与外设 FIFO 高速搬运;TZ 负责分配 GPI 通道权限(GPI Pipe 分配)
-
为什么设备树里叫
i2c_geni? 高通的 QUPv3 驱动在内核里的名字叫i2c_geni(或者是spi_geni)。这个GENI就是 Generic Interface(通用接口) 的缩写。它时刻在提醒你:它不是一个纯粹的 I2C 驱动,而是一个“把通用接口强行伪装成 I2C”的驱动。 -
为什么高通的 I2C 能调到惊人的高频,甚至容易波形畸变? 因为它是用高频流处理器模拟出来的时序。如果你的 Pinctrl(上拉电阻、驱动电流)和 QUPv3 的时钟分频没匹配好,由于它的硬件不是纯 ASIC,在高速传输下对电气特性的容错率有时比 STM32 还要敏感,因此在调眼镜的传感器和屏幕时,更需要死盯着 Pinctrl 的配置。
从本质和设计哲学上来说,高通的 QUPv3 串行引擎(Serial Engine)和树莓派 RP2040/RP2350 芯片里的 PIO(Programmable I/O,可编程输入输出)在思想上完全是同胞兄弟!
不过。。。
-
树莓派 PIO —— “轻量级、自由度极高的百变怪” 树莓派的 PIO 是完全对开发者开放的。你可以发挥无限的想象力,用 9 条汇编指令去手写任何奇葩的非标协议(比如强行用 PIO 去模拟一个 VGA 显卡信号,或者解码旧式红外遥控器)。它非常轻量,每个状态机只有几十个字的指令空间。
-
高通 QUPv3 —— “重量级、工业级标准的黑盒流处理器” 高通的 QUPv3 内部其实是一个非常复杂的 GENI(Generic Interface)状态机管理器。
-
不对外开放写汇编:高通不允许普通开发者自己去写 QUPv3 的底层汇编时序。高通已经把最标准的 I2C、SPI、UART、UART-LIN 等工业级标准协议的固件包全部写好、固化在系统底层了。
-
更高的吞吐量与 DMA 集成:QUPv3 内部深度绑定了高通专用的 BAM / GSI(Generic Software Interface)DMA 引擎。这意味着在 AR1+ 上,高通的 I2C/SPI 可以直接通过硬件 DMA 大批量、无感地向内存(DDR)吞吐传感器数据,其数据处理带宽和抗死锁能力,是 MCU 级别的 PIO 无法比拟的。
-

高通的QUP具有以下模式:
FIFO:CPU 轮询,低速调试、普通外设,HLOS 常规使用;
CPU_DMA:传统 CPU 侧 DMA;
GSI:硬件直通零 CPU 干预,高速、安全域 TZ 专用(指纹、NFC eSE)。

上面三种模式,FIFO模式和CPU_DMA模型切换,可以由驱动来完成。而GSI模式,需要在设备树中增加dmas配置。
统一兼容三大低速总线:
UART:波特率 300bps~4Mbps,支持 2 线无流控 / 4 线 CTS/RTS 硬件流控;
SPI:最高 50MHz,4~32bit 位宽,单总线最多 4 片选,支持全 / 半双工、半周期采样补偿;
I2C:标准多从设备总线,支持 400kHz 高速,适配触摸、传感器、EEPROM;
外设用途:蓝牙 HCI、触控、各类传感器、NFC、指纹、串口调试、运动控制。
| 协议 | 最大速率 | 关键特性 | 典型应用场景 |
|---|---|---|---|
| UART | 4 Mbps | 支持 HS (DMA) 和 LS (FIFO) 模式。 | 蓝牙 (WCN)、调试串口、IrDA。 |
| SPI | 50 MHz | 仅支持主模式;4-32 bit 数据宽度;可编程间隔。 | 传感器、指纹识别、触摸屏。 |
| I2C | 1 MHz | 支持标准 (100k)、快速 (400k)、快速+ (1M) 模式。 | 充电 IC、NFC、LED 驱动。 |
| I3C | 高于 I2C | 无需上拉电阻;性能更高。 | IMU 传感器 (传感枢纽)。 |
2 命令行操作
cat /sys/kernel/debug/pinctrl/f000000.pinctrl/pinmux-pins
输出是
sh-5.0# cat /sys/kernel/debug/pinctrl/*.pinctrl/pinmux-pins
Pinmux settings per pin
Format: pin (name): mux_owner gpio_owner hog?
pin 0 (GPIO_0): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 1 (GPIO_1): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 2 (GPIO_2): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 3 (GPIO_3): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 4 (GPIO_4): 984000.i2c (GPIO UNCLAIMED) function gpio group gpio4
pin 5 (GPIO_5): 984000.i2c (GPIO UNCLAIMED) function gpio group gpio5
pin 6 (GPIO_6): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 7 (GPIO_7): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 8 (GPIO_8): 990000.i2c (GPIO UNCLAIMED) function gpio group gpio8
pin 9 (GPIO_9): 990000.i2c (GPIO UNCLAIMED) function gpio group gpio9
pin 10 (GPIO_10): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 11 (GPIO_11): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 12 (GPIO_12): 994000.i2c (GPIO UNCLAIMED) function gpio group gpio12
pin 13 (GPIO_13): 994000.i2c (GPIO UNCLAIMED) function gpio group gpio13
pin 14 (GPIO_14): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 15 (GPIO_15): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 16 (GPIO_16): 998000.qcom,qup_uart (GPIO UNCLAIMED) function qup6 group gpio16
pin 17 (GPIO_17): 998000.qcom,qup_uart (GPIO UNCLAIMED) function qup6 group gpio17
pin 18 (GPIO_18): 998000.qcom,qup_uart (GPIO UNCLAIMED) function qup6 group gpio18
pin 19 (GPIO_19): 998000.qcom,qup_uart (GPIO UNCLAIMED) function qup6 group gpio19
pin 20 (GPIO_20): b0000000.qcom,cnss-qca6390 (GPIO UNCLAIMED) function gpio group gpio20
pin 21 (GPIO_21): vendor:bt_qca6390 (GPIO UNCLAIMED) function gpio group gpio21
pin 22 (GPIO_22): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 23 (GPIO_23): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 24 (GPIO_24): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 25 (GPIO_25): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 26 (GPIO_26): soc:wsa_spkr_en1_pinctrl (GPIO UNCLAIMED) function gpio group gpio26
pin 27 (GPIO_27): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 28 (GPIO_28): 980000.spi (GPIO UNCLAIMED) function gpio group gpio28
pin 29 (GPIO_29): 980000.spi (GPIO UNCLAIMED) function gpio group gpio29
pin 30 (GPIO_30): 980000.spi (GPIO UNCLAIMED) function gpio group gpio30
pin 31 (GPIO_31): 980000.spi (GPIO UNCLAIMED) function gpio group gpio31
pin 32 (GPIO_32): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 33 (GPIO_33): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 34 (GPIO_34): a90000.qcom,qup_uart (GPIO UNCLAIMED) function qup12 group gpio34
pin 35 (GPIO_35): a90000.qcom,qup_uart (GPIO UNCLAIMED) function qup12 group gpio35
pin 36 (GPIO_36): a94000.qcom,qup_uart (GPIO UNCLAIMED) function qup13 group gpio36
pin 37 (GPIO_37): a94000.qcom,qup_uart (GPIO UNCLAIMED) function qup13 group gpio37
pin 38 (GPIO_38): a94000.qcom,qup_uart (GPIO UNCLAIMED) function qup13 group gpio38
pin 39 (GPIO_39): a94000.qcom,qup_uart (GPIO UNCLAIMED) function qup13 group gpio39
pin 40 (GPIO_40): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 41 (GPIO_41): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 42 (GPIO_42): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 43 (GPIO_43): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 44 (GPIO_44): 884000.i2c (GPIO UNCLAIMED) function gpio group gpio44
pin 45 (GPIO_45): 884000.i2c (GPIO UNCLAIMED) function gpio group gpio45
pin 46 (GPIO_46): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 47 (GPIO_47): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 48 (GPIO_48): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 49 (GPIO_49): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 50 (GPIO_50): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 51 (GPIO_51): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 52 (GPIO_52): 88c000.spi (GPIO UNCLAIMED) function gpio group gpio52
pin 53 (GPIO_53): 88c000.spi (GPIO UNCLAIMED) function gpio group gpio53
pin 54 (GPIO_54): 88c000.spi (GPIO UNCLAIMED) function gpio group gpio54
pin 55 (GPIO_55): 88c000.spi (GPIO UNCLAIMED) function gpio group gpio55
pin 56 (GPIO_56): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 57 (GPIO_57): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 58 (GPIO_58): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 59 (GPIO_59): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 60 (GPIO_60): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 61 (GPIO_61): soc:display_gpio_regulator@1 f000000.pinctrl:389 function gpio group gpio61
pin 62 (GPIO_62): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 63 (GPIO_63): 2-002b f000000.pinctrl:391 function gpio group gpio63
pin 64 (GPIO_64): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 65 (GPIO_65): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 66 (GPIO_66): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 67 (GPIO_67): (MUX UNCLAIMED) f000000.pinctrl:395
pin 68 (GPIO_68): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 69 (GPIO_69): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 70 (GPIO_70): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 71 (GPIO_71): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 72 (GPIO_72): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 73 (GPIO_73): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 74 (GPIO_74): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 75 (GPIO_75): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 76 (GPIO_76): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 77 (GPIO_77): (MUX UNCLAIMED) f000000.pinctrl:405
pin 78 (GPIO_78): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 79 (GPIO_79): 1c00000.qcom,pcie f000000.pinctrl:407 function gpio group gpio79
pin 80 (GPIO_80): 1c00000.qcom,pcie (GPIO UNCLAIMED) function pci_e0 group gpio80
pin 81 (GPIO_81): 1c00000.qcom,pcie f000000.pinctrl:409 function gpio group gpio81
pin 82 (GPIO_82): 1c08000.qcom,pcie f000000.pinctrl:410 function gpio group gpio82
pin 83 (GPIO_83): 1c08000.qcom,pcie (GPIO UNCLAIMED) function pci_e1 group gpio83
pin 84 (GPIO_84): 1c08000.qcom,pcie f000000.pinctrl:412 function gpio group gpio84
pin 85 (GPIO_85): 1c10000.qcom,pcie f000000.pinctrl:413 function gpio group gpio85
pin 86 (GPIO_86): 1c10000.qcom,pcie (GPIO UNCLAIMED) function pci_e2 group gpio86
pin 87 (GPIO_87): 1c10000.qcom,pcie f000000.pinctrl:415 function gpio group gpio87
pin 88 (GPIO_88): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 89 (GPIO_89): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 90 (GPIO_90): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 91 (GPIO_91): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 92 (GPIO_92): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 93 (GPIO_93): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 94 (GPIO_94): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 95 (GPIO_95): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 96 (GPIO_96): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 97 (GPIO_97): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 98 (GPIO_98): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 99 (GPIO_99): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 100 (GPIO_100): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 101 (GPIO_101): (MUX UNCLAIMED) f000000.pinctrl:429
pin 102 (GPIO_102): (MUX UNCLAIMED) f000000.pinctrl:430
pin 103 (GPIO_103): (MUX UNCLAIMED) f000000.pinctrl:431
pin 104 (GPIO_104): (MUX UNCLAIMED) f000000.pinctrl:432
pin 105 (GPIO_105): (MUX UNCLAIMED) f000000.pinctrl:433
pin 106 (GPIO_106): (MUX UNCLAIMED) f000000.pinctrl:434
pin 107 (GPIO_107): (MUX UNCLAIMED) f000000.pinctrl:435
pin 108 (GPIO_108): (MUX UNCLAIMED) f000000.pinctrl:436
pin 109 (GPIO_109): (MUX UNCLAIMED) f000000.pinctrl:437
pin 110 (GPIO_110): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 111 (GPIO_111): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 112 (GPIO_112): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 113 (GPIO_113): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 114 (GPIO_114): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 115 (GPIO_115): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 116 (GPIO_116): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 117 (GPIO_117): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 118 (GPIO_118): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 119 (GPIO_119): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 120 (GPIO_120): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 121 (GPIO_121): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 122 (GPIO_122): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 123 (GPIO_123): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 124 (GPIO_124): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 125 (GPIO_125): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 126 (GPIO_126): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 127 (GPIO_127): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 128 (GPIO_128): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 129 (GPIO_129): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 130 (GPIO_130): soc:wsa_spkr_en2_pinctrl (GPIO UNCLAIMED) function gpio group gpio130
pin 131 (GPIO_131): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 132 (GPIO_132): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 133 (GPIO_133): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 134 (GPIO_134): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 135 (GPIO_135): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 136 (GPIO_136): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 137 (GPIO_137): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 138 (GPIO_138): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 139 (GPIO_139): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 140 (GPIO_140): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 141 (GPIO_141): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 142 (GPIO_142): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 143 (GPIO_143): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 144 (GPIO_144): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 145 (GPIO_145): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 146 (GPIO_146): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 147 (GPIO_147): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 148 (GPIO_148): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 149 (GPIO_149): (MUX UNCLAIMED) f000000.pinctrl:477
pin 150 (GPIO_150): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 151 (GPIO_151): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 152 (GPIO_152): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 153 (GPIO_153): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 154 (GPIO_154): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 155 (GPIO_155): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 156 (GPIO_156): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 157 (GPIO_157): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 158 (GPIO_158): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 159 (GPIO_159): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 160 (GPIO_160): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 161 (GPIO_161): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 162 (GPIO_162): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 163 (GPIO_163): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 164 (GPIO_164): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 165 (GPIO_165): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 166 (GPIO_166): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 167 (GPIO_167): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 168 (GPIO_168): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 169 (GPIO_169): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 170 (GPIO_170): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 171 (GPIO_171): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 172 (GPIO_172): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 173 (GPIO_173): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 174 (GPIO_174): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 175 (GPIO_175): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 176 (GPIO_176): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 177 (GPIO_177): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 178 (GPIO_178): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 179 (GPIO_179): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 180 (SDC2_CLK): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 181 (SDC2_CMD): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 182 (SDC2_DATA): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 183 (UFS_RESET): (MUX UNCLAIMED) f000000.pinctrl:511
可以看到,此时的QUP分配如下:
| 硬件 QUP 编号 | 内核物理基地址 (Hex) | 占用的物理引脚 (Pins) | 当前被激活的协议/功能 | 内核中的驱动设备节点名称 | 剩余未用引脚 (可当常规GPIO) |
| QUP_0 | 980000 |
GPIO 28, 29, 30, 31 | SPI 模式 (4线满载) | 980000.spi |
无(全被 SPI 占用) |
| QUP_1 | 984000 |
GPIO 4, 5, 6, 7 | I2C 模式 (仅用2线) | 984000.i2c |
GPIO 6, GPIO 7 |
| QUP_4 | 990000 |
GPIO 8, 9, 10, 11 | I2C 模式 (仅用2线) | 990000.i2c |
GPIO 10, GPIO 11 |
| QUP_5 | 994000 |
GPIO 12, 13, 14, 15 | I2C 模式 (仅用2线) | 994000.i2c |
GPIO 14, GPIO 15 |
| QUP_6 | 998000 |
GPIO 16, 17, 18, 19 | UART 模式 (4线带流控) | 998000.qcom,qup_uart |
无(全被 串口 占用) |
| QUP_12 | a90000 |
GPIO 32, 33, 34, 35 | UART 模式 (仅用2线) | a90000.qcom,qup_uart |
GPIO 32, GPIO 33 |
| QUP_13 | a94000 |
GPIO 36, 37, 38, 39 | UART 模式 (4线带流控) | a94000.qcom,qup_uart |
无(全被 串口 占用) |
| QUP_14 | 884000 |
GPIO 44, 45, 46, 47 | I2C 模式 (仅用2线) | 884000.i2c |
GPIO 46, GPIO 47 |
| QUP_15 | 88c000 |
GPIO 52, 53, 54, 55 | SPI 模式 (4线满载) | 88c000.spi |
无(全被 SPI 占用) |
3 配置
3.1 前置配置
主要有以下几个:
1 QUPAC 访问控制(QUPAC_Access.c)。全平台 SE 资源分配总入口,决定SE 归属 EE、协议、传输模式,核心数组字段:
{SE编号, 协议, 模式, 所有者AC, bAllowFifo, bLoad固件, bModExcl独占}
3 QUP SE 固件加载机制。每个 SE 必须加载对应协议固件(UART/SPI/I2C),固件存放路径common/core_qupv3fw/<芯片>/qupv3fw.elf。
3.2 协议配置
首先,目前没拿到板子,所有的操作都是根据网上或者AI来的。对于QUP,应该是自己不用写什么代码,基本上用设备树就可以了。这里主要有三个部分。
DTS 设备树(内核侧)。定义 SE 基地址、时钟、中断、状态status="ok"启用。
文件路径:
kernel/<version>/arch/arm64/boot/dts/vendor/qcom/<target>-qupv3.dtsi
- 找到对应的
qupv3_seX_protocol节点。- 将
status = "disabled";修改为status = "ok";。- 示例:
- &qupv3_se3_spi {
status = "ok";
pinctrl-0 = <&qup_se3_spi_active>;
pinctrl-1 = <&qup_se3_spi_sleep>;
pinctrl-names = "default", "sleep";
/* 指纹传感器挂载在 CS1 */
fingerprint@1 {
compatible = "qcom,fingerprint";
reg = <1>; /* <--- 这里必须改为 1,表示使用 CS1 */
spi-max-frequency = <24000000>;
/* 辅助引脚 */
interrupt-parent = <&tlmm>;
interrupts = <20 IRQ_TYPE_EDGE_RISING>;
};
};
Pinctrl 引脚配置。<芯片>-pinctrl.dtsi,配置 GPIO 复用功能、驱动强度、上下拉、休眠引脚状态。
在设备树中定义引脚的复用功能。
/* 示例:在 tlmm 节点下 */ qup_se3_spi_active: qup_se3_spi_active { mux { /* 增加 gpio41 */ pins = "gpio16", "gpio17", "gpio18", "gpio41"; function = "qup0_se3"; }; config { pins = "gpio16", "gpio17", "gpio18", "gpio41"; drive-strength = <16>; bias-disable; }; };
TZ 权限表。QUPAC_Access.c 分配 SE 归属、协议、GSI/FIFO 模式。
你必须修改 TZ 侧的配置文件,否则内核无法控制 SPI 控制器。
- 文件:
trustzone_images/core/settings/buses/qup_accesscontrol/qupv3/config/<target>/QUPAC_Access.c- 配置内容: 找到
QUP0_SE3对应的结构体,确保包含以下设置:
protocol设为QUPV3_PROTOCOL_SPImode通常设为QUPV3_MODE_GSI(指纹通常是大块数据传输) 或FIFOns_access设为ACCESS_FULL(允许非安全域即 Kernel 访问)
原来的DTS
&old_i2c_1 {
status = okay;
imu@68 { ... };
}
使用QUP I2C的DTS
&qupv3_se12_i2c { // 替换父节点为QUP I2C
status = "okay";
// 高通独有必须补充:双态pinctrl、时钟、DMA、电源域
pinctrl-names = "default", "sleep";
pinctrl-0 = <&qup12_active>;
pinctrl-1 = <&qup12_sleep>;
dmas = <&blsp_dma ...>, <&blsp_dma ...>;
clocks = <&gcc ...>, <&gcc ...>;
power-domains = <&rpmhpd ...>;
imu@68 { // 你的外设节点内容基本照搬旧平台
compatible = "xxx,mpu6050";
reg = <0x68>;
reset-gpios = <&tlmm ...>;
interrupts = <...>;
vdd-supply = <&pmic_lxx>;
qcom,slpi-vote; // 高通低功耗专属标签,按需加
};
}
或者SPI的例子
qupv3_se3_spi: spi@98c000 {
compatible = "qcom,spi-geni";
reg = <0x98c000 0x4000>;
#address-cells = <1>;
#size-cells = <0>;
reg-names = "se_phys";
interrupts = <GIC_SPI 604 IRQ_TYPE_LEVEL_HIGH>;
clock-names = "se-clk";
clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&qupv3_se3_spi_active>, <&qupv3_se3_spi_cs0_active>;
pinctrl-1 = <&qupv3_se3_spi_sleep>, <&qupv3_se3_spi_cs0_sleep>;
dmas = <&gpi_dma0 0 3 1 64 0>,
<&gpi_dma0 1 3 1 64 0>;
dma-names = "tx", "rx";
spi-max-frequency = <50000000>;
status = "disabled"; /* 需要在目标dts中 enable */
};
增加tlmm的配置
tlmm {
qup12_active: qup12_active {
pins = "gpioXX", "gpioYY";
function = "qup12"; // 复用为QUP I2C功能
drive-strength = <2>;
bias-pull-up;
};
qup12_sleep: qup12_sleep {
pins = "gpioXX", "gpioYY";
function = "gpio"; // 休眠切普通GPIO高阻输入
bias-disable;
};
};
之后要打开编译宏,不过我感觉一般都是开的。
CONFIG_I2C_QUP=y
CONFIG_BLSP_BAM=y
检查还是简单,编译出img后烧写即可。
烧录 dtb → dmesg | grep qup12
正常打印:qupv3_se12_i2c probe success、pinctrl state default selected;
报错:failed to get pinctrl state,就是 tlmm 里标签缺失 / 名字写错。
/* arch/arm64/boot/dts/qcom/你的单板.dts */
&qupv3_se3_spi {
status = "ok";
pinctrl-names = "default", "sleep";
pinctrl-0 = <&qup_se3_spi_active>;
pinctrl-1 = <&qup_se3_spi_sleep>;
/* 标准子节点写法 */
fingerprint@1 {
compatible = "goodix,gf3208"; /* 用于和 C 代码匹配的字符串 */
reg = <1>; /* 使用 CS1 片选线 */
spi-max-frequency = <24000000>; /* 24MHz,不需要在C代码里写死了 */
spi-cpol; /* 如果需要,可以在这里配置时钟极性 */
spi-cpha;
/* 辅助引脚 */
interrupt-parent = <&tlmm>;
interrupts = <20 IRQ_TYPE_EDGE_RISING>;
};
};
4 驱动示例
标准配置和驱动如下:
/* arch/arm64/boot/dts/qcom/你的单板.dts */
&qupv3_se3_spi {
status = "ok";
pinctrl-names = "default", "sleep";
pinctrl-0 = <&qup_se3_spi_active>;
pinctrl-1 = <&qup_se3_spi_sleep>;
/* 标准子节点写法 */
fingerprint@1 {
compatible = "goodix,gf3208"; /* 用于和 C 代码匹配的字符串 */
reg = <1>; /* 使用 CS1 片选线 */
spi-max-frequency = <24000000>; /* 24MHz,不需要在C代码里写死了 */
spi-cpol; /* 如果需要,可以在这里配置时钟极性 */
spi-cpha;
/* 辅助引脚 */
interrupt-parent = <&tlmm>;
interrupts = <20 IRQ_TYPE_EDGE_RISING>;
};
};
驱动,这种写法就是最为推荐的。
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/of.h>
/* 自定义的指纹设备结构体 */
struct gf_device {
struct spi_device *spi;
void *spi_buffer;
/* 其他成员如 gpio, irq 等 */
};
/* 1. 标准的 Probe 初始化函数 */
static int gf_spi_probe(struct spi_device *spi)
{
struct gf_device *gf_dev;
dev_info(&spi->dev, "gf_spi probe started!\n");
/* 分配驱动私有结构体 */
gf_dev = devm_kzalloc(&spi->dev, sizeof(*gf_dev), GFP_KERNEL);
if (!gf_dev)
return -ENOMEM;
/* 核心:内核已经把设备树里的参数(CS=1, 速度=24M)全部解析好并填进 spi 指针里了! */
gf_dev->spi = spi;
spi_set_drvdata(spi, gf_dev); /* 将私有数据挂载到 spi 设备中 */
/* 分配缓冲区 */
gf_dev->spi_buffer = devm_kzalloc(&spi->dev, 4096, GFP_KERNEL);
if (!gf_dev->spi_buffer)
return -ENOMEM;
/* 在这里继续初始化字符设备、注册中断等操作... */
dev_info(&spi->dev, "gf_spi probed successfully on CS%d\n", spi->chip_select);
return 0;
}
/* 2. 标准的 Remove 卸载函数 */
static int gf_spi_remove(struct spi_device *spi)
{
struct gf_device *gf_dev = spi_get_drvdata(spi);
/* 释放资源(注:使用 devm_ 开头的内存分配函数会在卸载时自动释放,无需手动 kfree) */
return 0;
}
/* 3. 设备树匹配表(必须与 DTS 中的 compatible 一致) */
static const struct of_device_id gf_spi_of_match[] = {
{ .compatible = "goodix,gf3208", },
{ /* 哨兵,必须留空 */ }
};
MODULE_DEVICE_TABLE(of, gf_spi_of_match);
/* 4. 传统的本地匹配表(防老版本内核或非DT平台兼容) */
static const struct spi_device_id gf_spi_id[] = {
{ "gf_spi", 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, gf_spi_id);
/* 5. 标准的 SPI 驱动结构体 */
static struct spi_driver gf_spi_driver = {
.driver = {
.name = "goodix_fp",
.of_match_table = gf_spi_of_match, /* 绑定设备树匹配表 */
},
.probe = gf_spi_probe,
.remove = gf_spi_remove,
.id_table = gf_spi_id,
};
/* 6. 宏函数:自动生成 module_init 和 module_exit,一键注册 */
module_spi_driver(gf_spi_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Author");
MODULE_DESCRIPTION("Standard Goodix SPI Driver");
此时,可以直接在驱动中控制,这种写法野一些。下面是一个SPI驱动的例子。
void gf_reg_spi_driver(struct gf_device *gf_dev)
{
struct device_node *np = NULL;
struct platform_device *pdev = NULL;
struct spi_controller *ctlr = NULL;
struct spi_device *spi = NULL;
/* 1. 查找SPI控制器 */
np = of_find_compatible_node(NULL, NULL, "qcom,spi-geni");
while (np) {
u32 reg = 0;
of_property_read_u32(np, "reg", ®);
if (reg == 0x98c000) { /* SE3的基地址 */
/* 2. 获取platform_device */
pdev = of_find_device_by_node(np); /* 需要 #include <linux/of_platform.h> */
if (pdev) {
/* 3. 获取spi_controller */
ctlr = platform_get_drvdata(pdev);
if (ctlr) {
/* 4. 分配并添加SPI设备 */
spi = spi_alloc_device(ctlr);
if (spi) {
spi->chip_select = 0;
spi->max_speed_hz = 50000000;
spi->mode = SPI_MODE_0;
spi->bits_per_word = 8;
strlcpy(spi->modalias, "gf_spi", sizeof(spi->modalias));
if (spi_add_device(spi) == 0) {
gf_dev->spi = spi;
gf_dev->spi_buffer = kzalloc(4096, GFP_KERNEL);
}
}
}
}
of_node_put(np);
return;
}
np = of_find_compatible_node(np, NULL, "qcom,spi-geni");
}
}
无法发现 SPI 设备: 检查 dmesg | grep spi,看是否有 qup_geni_spi 的报错。如果有 "access denied",说明 TZ 配置没生效。
这部分主要还是要看高通的文档。详细的UART,I2C的配置,后面再看写不写吧。
更多推荐

所有评论(0)