3. 设备树配置详解:全志T113 SPI设备树节点解析
设备树,说白了就是告诉内核“你的硬件长什么样”。我刚开始接触Linux驱动时,总觉得设备树是个黑盒子。后来调过几块板子才明白——设备树配错了,驱动写得再好也白搭。
这一节,我们专门拆解全志T113的SPI设备树节点。时钟怎么配?DMA要不要开?片选引脚怎么接?一个一个说清楚。
3.1 SPI设备树节点整体结构
全志T113的SPI控制器在设备树里通常叫 spi0、spi1。每个控制器对应一组硬件寄存器、时钟源和引脚。先看一个完整的节点示例:
spi0: spi@05010000 {
compatible = "allwinner,sun8i-spi";
reg = <0x05010000 0x1000>;
interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
clocks = <>;
clock-names = "ahb", "mod";
resets = <>;
dmas = <&dma 1>, <&dma 1>;
dma-names = "rx", "tx";
pinctrl-0 = <&spi0_pins_a>;
pinctrl-names = "default";
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
};
这个节点里,每一行都有讲究。我挑几个关键字段拆开讲。
3.2 时钟配置:别让SPI跑在错误频率上
时钟是SPI通信的“心跳”。T113的SPI控制器需要两个时钟:AHB总线时钟和模块时钟。
| 时钟名称 | 作用 | 典型频率 |
|---|---|---|
| ahb | SPI控制器访问AHB总线 | 200MHz |
| mod | SPI模块内部逻辑时钟 | 100MHz |
关键点:SPI的SCLK频率由mod时钟分频得到。比如mod时钟100MHz,分频系数4,SCLK就是25MHz。我见过有人把mod时钟配成24MHz,结果SCLK最高只能到6MHz,白白浪费了T113的SPI性能。
时钟节点引用示例:
clocks = <>;
clock-names = "ahb", "mod";
这里 CCU_CLK_BUS_SPI0 是AHB时钟门控,CCU_CLK_SPI0 是模块时钟。具体宏定义在 sun8i-t113.h 头文件里。嗯,配时钟时记得核对数据手册里的时钟树,别想当然。
3.3 DMA配置:什么时候该开?什么时候不该开?
DMA能解放CPU,但不是所有场景都需要。我个人习惯:
- 大块数据搬运(比如SPI Flash读写、LCD刷屏)→ 开DMA
- 小数据量、高频次(比如传感器寄存器读写)→ 关DMA,用PIO
DMA节点配置示例:
dmas = <&dma 1>, <&dma 1>;
dma-names = "rx", "tx";
这里 &dma 1 表示使用DMA控制器1的通道。注意:全志的DMA通道分配有固定映射,SPI0的RX/TX通道号在数据手册里有明确说明。我曾经踩过一个坑——把通道号写反了,结果RX数据一直读不到,查了两天才发现是DMA通道配错了。
避坑指南:如果SPI设备不支持DMA突发传输,或者你的SPI从机响应时间不确定,建议关掉DMA。否则DMA超时会导致整个SPI总线卡死。我曾经在调试一个温湿度传感器时遇到过,最后老老实实改回PIO模式。
3.4 片选引脚配置:GPIO还是硬件CS?
片选引脚是SPI通信的“开关”。T113支持两种模式:
- 硬件CS:由SPI控制器自动控制,配置在pinctrl里
- 软件CS:用普通GPIO模拟,手动拉高拉低
硬件CS配置示例:
spi0_pins_a: spi0-pins {
pins = "PC0", "PC1", "PC2", "PC3";
function = "spi0";
};
这里PC0是SCLK,PC1是MOSI,PC2是MISO,PC3是CS。注意:硬件CS的极性由控制器寄存器控制,设备树里不需要额外配置。
软件CS配置示例:
spi0_pins_b: spi0-pins {
pins = "PC0", "PC1", "PC2";
function = "spi0";
};
cs-gpios = <&pio PC 3 GPIO_ACTIVE_LOW>;
软件CS的好处是灵活——你可以用任意GPIO做片选,甚至一个SPI总线上挂多个设备,每个设备用不同的GPIO。但代价是每次传输前要手动拉低CS,传输完再拉高,多了一次GPIO操作的开销。
我的建议:如果SPI总线上只挂一个设备,用硬件CS就够了。如果挂多个设备,或者从机对CS时序有特殊要求(比如需要CS保持低电平超过一个字节时间),那就用软件CS。我在一个项目里同时挂了SPI Flash和LCD,两个设备片选用不同GPIO,软件控制,稳得很。
3.5 完整节点实战:一个SPI Flash的配置
把上面讲的串起来,配一个SPI NOR Flash的完整节点:
&spi0 {
status = "okay";
pinctrl-0 = <&spi0_pins_a>;
pinctrl-names = "default";
dmas = <&dma 1>, <&dma 1>;
dma-names = "rx", "tx";
flash@0 {
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <50000000>;
spi-tx-bus-width = <4>;
spi-rx-bus-width = <4>;
};
};
这里 spi-max-frequency 设成50MHz,对应mod时钟100MHz、分频2。注意:实际能达到的频率还受PCB走线长度、负载电容影响。我测过T113的SPI0,在50MHz下跑Quad SPI读,实测速度能到45MB/s左右。
性能调优提示:如果SPI Flash支持Dual/Quad模式,记得配 spi-tx-bus-width 和 spi-rx-bus-width。默认是1(单线),改成4后读写速度能翻倍。但前提是Flash芯片支持,且PCB上把四根数据线都连好了。
3.6 设备树配置核心逻辑图
下面这张图总结了SPI设备树配置的完整流程和关键决策点:
3.7 常见错误与排查方法
设备树配错了,内核启动时会有提示。我总结了几种常见错误:
| 错误现象 | 可能原因 | 排查方法 |
|---|---|---|
| SPI设备未注册 | status = "disabled" 或 compatible 不匹配 | 检查设备树status字段,确认驱动加载 |
| SCLK频率不对 | mod时钟配置错误或分频系数不对 | 用示波器测SCLK引脚,对比预期值 |
| DMA传输卡死 | DMA通道号错误或从机不支持突发 | 关掉DMA改用PIO测试,排除DMA问题 |
| 片选信号异常 | GPIO复用配置错误或极性不对 | 检查pinctrl配置,用逻辑分析仪看CS波形 |
调试小技巧:内核启动时加 earlycon 和 ignore_loglevel 参数,能看到更详细的设备树解析日志。如果SPI设备没注册,先确认 /sys/bus/spi/devices/ 目录下有没有设备节点。没有?那就是设备树没解析成功。