AM335x CPSW 寄存器模块详细功能说明
一、CPSW 子系统整体架构
AM335x 集成了一个三端口交换子系统(3-Port Switch, CPSW),由多个子模块协同完成以太网帧的收发、交换、地址学习和管理功能。
AM335x CPSW 子系统 (基地址 0x4A100000)
┌─────────────────────────────────────────────────────────────────────────────┐
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────────────────┐ │
│ │ CPSW_SS │ │ CPSW_WR │ │ CPSW_PORT │ │
│ │ 0x4A100000│ │ 0x4A101200│ │ 0x4A100100 │ │
│ │ 系统控制 │ │ 中断控制 │ │ ┌──────┬──────┬──────┐ │ │
│ └──────────┘ └──────────┘ │ │ P0 │ P1 │ P2 │ │ │
│ │ │ Host │百兆口│千兆口│ │ │
│ │ └──┬───┴──┬───┴──┬───┘ │ │
│ └─────┼──────┼──────┼──────┘ │
│ │ │ │ │
│ ┌────▼──────▼──────▼────┐ │
│ │ CPSW_ALE │ │
│ │ 0x4A100D00 │ │
│ │ 地址查找/交换引擎 │ │
│ └───────────────────────┘ │
│ │ │ │
│ ┌──────────▼──┐ ┌─▼───────────┐ │
│ │ CPSW_SL1 │ │ CPSW_SL2 │ │
│ │ 0x4A100D80 │ │ 0x4A100DC0 │ │
│ │ 百兆MAC │ │ 千兆MAC │ │
│ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │
│ │ RMII │ RGMII2 │
│ ▼ ▼ │
│ JL1111 RTL8211F │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ CPDMA │ │ STATERAM │ │ STATS │ │ MDIO │ │
│ │ 0x4A100800│ │ 0x4A100A00│ │ 0x4A100900│ │ 0x4A101000│ │
│ │ DMA引擎 │ │ DMA状态 │ │ 统计信息 │ │ PHY管理 │ │
│ └────┬─────┘ └────┬─────┘ └──────────┘ └──────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────────────┐ │
│ │ CPPI RAM │ │
│ │ 0x4A102000 │ │
│ │ 收发描述符内存 (8KB) │ │
│ └──────────────────────────┘ │
│ │
│ ========= 外部模块 ========= │
│ ┌──────────┐ ┌──────────────┐ │
│ │Ctrl Module│ │ GPIO │ │
│ │0x44E10000 │ │ 0x44E07000等 │ │
│ │Pin Mux等 │ │ PHY复位/中断 │ │
│ └──────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
二、各寄存器模块详细说明
2.1 CPSW_SS — 交换子系统控制 (0x4A100000)
功能概述:整个 CPSW 三端口交换子系统的顶层控制模块,负责全局复位和统计使能。
宏定义:
#define CPSW_SS___S___(ofs, val) REG32___S___(0x4A100000 + (ofs), val)
#define CPSW_SS_M_S_WZ(ofs, mask, val) REG32_M_S_WZ(0x4A100000 + (ofs), mask, val)
代码中使用的关键寄存器:
| 偏移 | 寄存器名 | 读写 | 功能说明 | 代码中的使用场景 |
|---|---|---|---|---|
| 0x0C | STAT_PORT_EN | R/W | 统计端口使能。bit0=P0(Host), bit1=P1(百兆), bit2=P2(千兆)。使能后对应端口的收发帧计数器才开始工作 | CpswSsReset():写 _B(0)|_B(1)|_B(2) 使能全部三个端口的统计 |
在数据流中的角色:SS模块本身不参与数据收发,而是作为全局开关。如果不执行SS复位,其他子模块的状态可能不确定,导致驱动行为异常。
2.2 CPSW_PORT — 端口配置 (0x4A100100)
功能概述:配置三个交换端口(P0=Host主机端口、P1=百兆外部端口、P2=千兆外部端口)的VLAN、MAC地址、FIFO策略和最大帧长度等参数。
宏定义:
#define CPSW_PORT___S___(ofs, val) REG32___S___(0x4A100100 + (ofs), val)
#define CPSW_PORT_M_S___(ofs, mask, val) REG32_M_S___(0x4A100100 + (ofs), mask, val)
#define CPSW_PORT_M_G___(ofs, mask) REG32_M_G___(0x4A100100 + (ofs), mask)
代码中使用的关键寄存器:
| 偏移 | 寄存器名 | 所属端口 | 功能说明 | 代码使用场景 |
|---|---|---|---|---|
| 0x14 | P0_PORT_VLAN | P0 | Host端口默认VLAN。bit[11:0]=VLAN ID, bit[15:13]=优先级 | 设为0x0,Host端口不带VLAN标签 |
| 0x114 | P1_PORT_VLAN | P1 | 百兆口默认VLAN | 设为0x1,百兆口默认VLAN ID = 1 |
| 0x120 | P1_SA_LO | P1 | 百兆口源MAC地址低16位。bit[15:8]=MAC[0], bit[7:0]=MAC[1] | CpswPortMacSet(1, mac):写入百兆口MAC |
| 0x124 | P1_SA_HI | P1 | 百兆口源MAC地址高32位。bit[31:24]=MAC[2], ..., bit[7:0]=MAC[5] | 同上 |
| 0x214 | P2_PORT_VLAN | P2 | 千兆口默认VLAN(仅P4板) | 设为0x2,千兆口默认VLAN ID = 2 |
| 0x220 | P2_SA_LO | P2 | 千兆口源MAC地址低16位 | CpswPortMacSet(2, mac) |
| 0x224 | P2_SA_HI | P2 | 千兆口源MAC地址高32位 | 同上 |
在数据流中的角色:
发送路径: CPU → P0(Host Port) → ALE查找 → P1或P2(外部端口) → PHY → 网线
接收路径: 网线 → PHY → P1或P2(外部端口) → ALE查找 → P0(Host Port) → CPDMA → CPU
P0_TX_IN_CTL 的双MAC模式确保:
- P1和P2各自有独立的发送FIFO队列
- 不会因为一个端口阻塞而影响另一个端口的发送
VLAN隔离机制:
VLAN 1 (百兆域) VLAN 2 (千兆域)
┌─────────────┐ ┌─────────────┐
│ P0 ←→ P1 │ │ P0 ←→ P2 │
│ (Host 百兆) │ │ (Host 千兆) │
└─────────────┘ └─────────────┘
百兆口收到的包只能到P0(CPU),不会转发到P2(千兆口)
千兆口收到的包只能到P0(CPU),不会转发到P1(百兆口)
→ 通过ALE VLAN表项实现端口隔离
2.3 CPDMA — DMA控制引擎 (0x4A100800)
功能概述:CPDMA(Communications Port DMA)是CPSW的DMA引擎,负责在主机内存和CPSW之间搬运以太网帧数据。它管理8个TX通道和8个RX通道的DMA传输控制、中断产生和帧缓冲区偏移配置。
宏定义:
#define CPDMA___S___(ofs, val) REG32___S___(0x4A100800 + (ofs), val)
#define CPDMA_M_S___(ofs, mask, val) REG32_M_S___(0x4A100800 + (ofs), mask, val)
#define CPDMA_M_S_WZ(ofs, mask, val) REG32_M_S_WZ(0x4A100800 + (ofs), mask, val)
代码中使用的关键寄存器:
| 偏移 | 寄存器名 | 读写 | 功能说明 | 代码使用场景 |
|---|---|---|---|---|
| 0x14 | RX_CONTROL | R/W | RX DMA全局使能。bit0: 0=禁用, 1=启用接收DMA | CpdmaReset():写1启用。DeviceInit()中再次确认启用 |
| 0x1C | CPDMA_SOFT_RESET | R/W | DMA软复位。写1触发,等待变0 | CpdmaReset():初始化首步 |
| 0x28 | RX_BUFFER_OFFSET | R/W | 接收缓冲区偏移。bit[15:0]指定帧数据在缓冲区中的起始偏移 | CpdmaReset():写0,数据从缓冲区首字节开始 |
| 0x88 | TX_INTMASK_SET | R/W | TX中断掩码设置。每位对应一个TX通道 | CpdmaReset():写0,不启用TX中断(采用轮询方式检查发送完成) |
| 0x94 | CPDMA_EOI_VECTOR | R/W | 中断结束向量。写入中断类型编号以确认中断处理完成,允许产生后续中断 | 每次中断ISR结尾必须写入对应类型值 |
| 0xA8 | RX_INTMASK_SET | R/W | RX中断掩码设置。每位对应一个RX通道 | CpdmaReset():写bit0,仅启用通道0的RX中断 |
EOI_VECTOR 值定义(写入0x94偏移):
| 值 | 宏定义 | 含义 | 使用场景 |
|---|---|---|---|
| 1 | AM335X_ETH_INTTYPE_RX_PULSE | RX包中断结束 | RX ISR结尾 |
| 2 | AM335X_ETH_INTTYPE_TX_PULSE | TX中断结束 | TX ISR结尾 |
| 3 | AM335X_ETH_INTTYPE_MISC_PULSE | MISC中断结束 | MISC ISR结尾(PHY链路变化等) |
在数据流中的角色:
发送流程:
CPU填充描述符 → 写TX_HDP[ch]启动DMA → CPDMA读取描述符链 →
从m_Buf读数据 → 推入CPSW发送FIFO → 清除Ownership位 → 设置EOQ
接收流程:
CPSW收到帧 → CPDMA查找空闲RX描述符(Ownership=1) →
写入m_Buf → 填写帧长和标志 → 清除Ownership → 触发RX中断 →
CPU读取数据 → 回收描述符(重设Ownership=1, 重新挂入链表尾部)
2.4 CPDMA_STATERAM — DMA状态寄存器 (0x4A100A00)
功能概述:维护每个DMA通道的头描述符指针(HDP)和完成指针(CP)。HDP是DMA引擎的"发令枪",写入非零地址即启动该通道的DMA操作;CP用于中断确认和发送完成检测。
宏定义:
#define CPSW_TX_HDP___G___(ch) REG32___G___(0x4A100A00 + (ch) * 4)
#define CPSW_TX_HDP___S___(ch, val) REG32___S___(0x4A100A00 + (ch) * 4, val)
#define CPSW_RX_HDP___G___(ch) REG32___G___(0x4A100A20 + (ch) * 4)
#define CPSW_RX_HDP___S___(ch, val) REG32___S___(0x4A100A20 + (ch) * 4, val)
#define CPSW_TX_CP___G___(ch) REG32___G___(0x4A100A40 + (ch) * 4)
#define CPSW_TX_CP___S___(ch, val) REG32___S___(0x4A100A40 + (ch) * 4, val)
#define CPSW_RX_CP___G___(ch) REG32___G___(0x4A100A60 + (ch) * 4)
#define CPSW_RX_CP___S___(ch, val) REG32___S___(0x4A100A60 + (ch) * 4, val)
完整寄存器映射:
| 偏移范围 | 寄存器组 | 通道数 | 说明 |
|---|---|---|---|
| 0xA20~0xA3C | RX_HDP[0~7] | 8 | RX头描述符指针。写入描述符地址启动接收 |
| 0xA40~0xA5C | TX_CP[0~7] | 8 | TX完成指针。DMA完成后硬件更新 |
| 0xA60~0xA7C | RX_CP[0~7] | 8 | RX完成指针。DMA完成后硬件更新,写回以确认 |
本驱动的通道使用方案:
| 通道 | TX用途 | RX用途 |
|---|---|---|
| 1 | Port2(千兆)发送 | 未使用 |
| 2~7 | 未使用 | 未使用 |
HDP/CP 在收发中的工作机制:
TX发送启动:
┌──────────────────────────────────────────────────────┐
│ 1. CPU准备好描述符链(设置SOP/EOP/Ownership/To_Port) │
│ 2. 写 TX_HDP[ch] = 第一个描述符的地址 │
│ 3. DMA引擎开始遍历描述符链,逐个发送 │
│ 4. 发送完成后,DMA清除Ownership位 │
│ 5. 到达链尾(NextDesc=NULL),DMA设置EOQ位并停止 │
│ 6. TX_HDP[ch] 自动变为0 │
└──────────────────────────────────────────────────────┘
RX接收启动:
┌──────────────────────────────────────────────────────┐
│ 1. CPU准备好空描述符链(设置Ownership=1, BufLen) │
│ 2. 写 RX_HDP[0] = 第一个描述符的地址 │
│ 3. 收到帧 → DMA写入缓冲区,填写帧长/From_Port等 │
│ 4. DMA清除Ownership位,更新RX_CP[0] │
│ 5. 触发RX中断 │
│ 6. ISR中:读RX_CP[0],写回RX_CP[0]确认 │
│ 7. CPU处理数据后,回收描述符挂到链尾 │
└──────────────────────────────────────────────────────┘
2.5 CPSW_ALE — 地址查找引擎 (0x4A100D00)
功能概述:ALE(Address Lookup Engine)是CPSW的核心交换引擎,负责根据MAC地址和VLAN进行帧转发决策。它维护一个1024条目的地址表,支持学习、老化、VLAN过滤和多播/广播泛洪。
宏定义:
#define CPSW_ALE___S___(ofs, val) REG32___S___(0x4A100D00 + (ofs), val)
#define CPSW_ALE_M_S___(ofs, mask, val) REG32_M_S___(0x4A100D00 + (ofs), mask, val)
#define CPSW_ALE___G___(ofs) REG32___G___(0x4A100D00 + (ofs))
代码中使用的关键寄存器:
| 偏移 | 寄存器名 | 功能说明 | 代码使用场景 |
|---|---|---|---|
| 0x10 | ALE_PRESCALE | ALE预分频器。bit[19:0]控制老化和速率限制的时间基准 | 初始化时设为0xFFFFF |
| 0x20 | ALE_TBLCTL | 表控制。bit31=写(1)/读(0), bit[9:0]=表项索引 | 读写ALE表项时使用 |
| 0x34 | ALE_TBLW2 | 表字2 (bit 71:64) | 写入/读出ALE表项的高8位 |
| 0x38 | ALE_TBLW1 | 表字1 (bit 63:32) | 写入/读出ALE表项的中32位 |
| 0x3C | ALE_TBLW0 | 表字0 (bit 31:0) | 写入/读出ALE表项的低32位 |
| 0x40+n*4 | ALE_PORTCTL[n] | 端口n控制。bit[1:0]=转发状态(0x03=Forward), bit11=MAC_ONLY | 所有端口设为Forward模式 |
ALE 表项结构(72位):
本驱动使用两种表项类型:
VLAN 表项 (EntryType=2):
71 62 61-60 59--------48 47---27 26----24 23-19 18---16 15-11 10---8 7-3 2---0
┌─────────┬──────┬───────────────┬────────┬─────────┬──────┬────────┬──────┬───────┬─────┬──────┐
│Reserved │Type=2│ VLAN ID │Reserved│ForceUntag│Rsrvd │RegMcast│Rsrvd │UnregMc│Rsrvd│Member│
│ │ │ (12bit) │ │ Egress │ │FloodMsk│ │FldMsk │ │ List │
└─────────┴──────┴───────────────┴────────┴─────────┴──────┴────────┴──────┴───────┴─────┴──────┘
| 表项索引 | VLAN ID | 成员端口 | 说明 |
|---|---|---|---|
| 2 | 2 | P0+P2 (0x05) | 千兆VLAN:Host端口和Port2互通 |
VLAN 单播表项 (EntryType=3):
71-68 67---66 65 64 63-62 61-60 59--------48 47-----------------------------------------0
┌──────┬────────┬────┬──────┬──────┬──────┬───────────────┬──────────────────────────────────────────┐
│Rsrvd │PortNum │Blk │Secure│UcType│Type=3│ VLAN ID │ 48-bit MAC Address │
│ │(转发至) │ │ │ │ │ (12bit) │ │
└──────┴────────┴────┴──────┴──────┴──────┴───────────────┴──────────────────────────────────────────┘
| 表项索引 | VLAN ID | MAC地址 | PortNum | 说明 |
|---|---|---|---|---|
| 3 | 2 | D2:72:22:50:00:81 | 0 (Host) | 千兆口MAC,收到目标为此MAC的帧转发到CPU |
ALE在数据流中的角色:
接收帧到达时:
帧进入Port1/Port2 → ALE提取源MAC和目标MAC →
┌─ 目标MAC匹配单播表项 → 转发到表项指定的端口(Host Port 0)
├─ 目标MAC是广播地址 → 按VLAN成员列表泛洪
├─ 目标MAC是多播地址 → 按多播泛洪掩码转发
└─ 目标MAC未匹配 → 按未注册多播泛洪掩码处理
发送帧离开时:
CPU通过CPDMA发送 → 描述符中To_Port_En=1, To_Port=1或2 →
ALE仍执行查找,但定向发送优先 → 帧从指定端口发出
2.6 CPSW_SL1 / CPSW_SL2 — MAC Sliver (0x4A100D80 / 0x4A100DC0)
功能概述:Sliver(薄片)是每个外部端口的MAC层控制器,负责管理物理链路参数:速度、双工模式、GMII使能、流控和环回等。每个外部端口有一个独立的Sliver。
宏定义:
// slIdx: 0=SL1(百兆), 1=SL2(千兆)
#define CPSW_SL_M_S___(slIdx, ofs, mask, val) REG32_M_S___(0x4A100D80 + (slIdx)*0x40 + (ofs), mask, val)
#define CPSW_SL_M_S_WZ(slIdx, ofs, mask, val) REG32_M_S_WZ(0x4A100D80 + (slIdx)*0x40 + (ofs), mask, val)
地址映射:
| Sliver | 基地址 | slIdx | 对应端口 |
|---|---|---|---|
| SL2 | 0x4A100DC0 | 1 | Port2 千兆口 |
代码中使用的关键寄存器:
| 偏移 | 寄存器名 | 功能说明 | 代码使用场景 |
|---|---|---|---|
| 0x0C | SOFT_RESET | Sliver软复位。写1,等待变0 | CpswSlReset():端口初始化时复位MAC层 |
MACCONTROL 各位详解(偏移 0x04):
| 位 | 字段 | 说明 | 10M半双工 | 10M全双工 | 100M半双工 | 100M全双工 | 1000M半双工 | 1000M全双工 |
|---|---|---|---|---|---|---|---|---|
| 16 | IFCTL_B | RMII速度选择:0=10M, 1=100M | 0 | 0 | 1 | 1 | 0 | 0 |
| 15 | IFCTL_A | RMII速度选择(与IFCTL_B相同) | 0 | 0 | 1 | 1 | 0 | 0 |
| 7 | GIG | 千兆模式:0=10/100M, 1=1000M | 0 | 0 | 0 | 0 | 1 | 1 |
| 5 | GMII_EN | MAC收发使能(所有模式必须=1) | 1 | 1 | 1 | 1 | 1 | 1 |
| 0 | FULLDUPLEX | 双工选择:0=半双工, 1=全双工 | 0 | 1 | 0 | 1 | 0 | 1 |
在数据流中的角色:
Sliver是MAC层的"最后一道关卡"。GMII_EN=0时,无论CPDMA如何操作,帧都无法从物理端口发出或接收。PHY线程检测到链路变化后,通过此寄存器告知MAC当前链路的速度和双工模式,MAC据此调整时序。
PHY线程检测到链路UP(100M全双工) →
CpswSlLinkModeSet(slIdx=0, kEthLinkMode100MFullDuplex) →
写 SL1 MACCONTROL = IFCTL_B | IFCTL_A | GMII_EN | FULLDUPLEX
即 bit16 | bit15 | bit5 | bit0 = 0x18021
2.7 MDIO — PHY管理接口 (0x4A101000)
功能概述:MDIO(Management Data Input/Output)模块通过两线串行总线(MDC/MDIO)访问外部PHY芯片的寄存器,用于PHY配置、状态查询和链路监控。两个PHY共享同一个MDIO控制器,通过不同的PHY地址区分。
宏定义:
#define MDIO___S___(ofs, val) REG32___S___(0x4A101000 + (ofs), val)
#define MDIO_M_S___(ofs, mask, val) REG32_M_S___(0x4A101000 + (ofs), mask, val)
#define MDIO_M_G___(ofs, mask) REG32_M_G___(0x4A101000 + (ofs), mask)
#define MDIO_M___WZ(ofs, mask) REG32_M___WZ(0x4A101000 + (ofs), mask)
代码中使用的关键寄存器:
| 偏移 | 寄存器名 | 功能说明 | 代码使用场景 |
|---|---|---|---|
| 0x10 | LINKINTRAW | 链路中断原始状态。bit0=PHYSEL0(百兆PHY), bit1=PHYSEL1(千兆PHY)。写1清除 | MiscIntDeal():判断哪个PHY产生链路变化 |
| 0x20 | USERINTRAW | 用户命令完成中断原始状态。bit0=ACCESS0完成, bit1=ACCESS1完成。写1清除 | MdioUserIntClr() |
| 0x80 | USERACCESS0 | 用户访问寄存器0。bit31=GO(启动), bit30=WRITE(写模式), bit29=ACK(读确认), bit[25:21]=RegAddr, bit[20:16]=PhyAddr, bit[15:0]=Data | MdioRead()/MdioWrite():读写PHY寄存器 |
| 0x84 | USERPHYSEL0 | PHY选择0。bit6=链路中断使能, bit[4:0]=监控的PHY地址 | MdioConfigPhyMonitor(1,1):监控PHY地址1(百兆) |
| 0x8C | USERPHYSEL1 | PHY选择1。同上 | MdioConfigPhyMonitor(2,2):监控PHY地址2(千兆) |
MDIO读写时序:
MDIO读操作 (MdioRead):
1. 等待 USERACCESS0.GO == 0 (上次操作完成)
2. 写 USERACCESS0 = GO(1) | WRITE(0) | RegAddr | PhyAddr
3. 等待 USERACCESS0.GO == 0 (本次操作完成)
4. 检查 ACK位:
ACK=1 → 读取 DATA[15:0] 返回
ACK=0 → 返回-1 (PHY无应答)
MDIO写操作 (MdioWrite):
1. 等待 USERACCESS0.GO == 0
2. 写 USERACCESS0 = GO(1) | WRITE(1) | RegAddr | PhyAddr | Data
3. 等待 USERACCESS0.GO == 0
PHY监控机制:
MDIO控制器内置PHY链路监控状态机:
┌────────────────────────────────────────────────────────┐
│ USERPHYSEL0 (偏移0x84) │
│ 监控 PHY地址=1 (百兆JL1111) │
│ 链路状态变化 → 置位 LINKINTRAW.bit0 │
│ → 触发 CPSW_WR MISC中断 │
│ → EthCpswMiscIsr │
│ → EthPhyEventSend(1) │
│ → PHY线程被唤醒,读取PHY寄存器确认链路状态 │
├────────────────────────────────────────────────────────┤
│ USERPHYSEL1 (偏移0x8C) │
│ 监控 PHY地址=2 (千兆RTL8211F) │
│ 链路状态变化 → 置位 LINKINTRAW.bit1 │
│ → 同上流程,EthPhyEventSend(2) │
└────────────────────────────────────────────────────────┘
2.8 CPSW_WR — 中断包装器 (0x4A101200)
功能概述:WR(Wrapper)模块是CPSW中断系统的路由和使能控制器。它将CPDMA产生的各类中断(RX/TX/Threshold/Misc)路由到ARM Cortex-A8的中断控制器,并提供中断状态查询接口。
宏定义:
#define CPSW_WR_M_S___(ofs, mask, val) REG32_M_S___(0x4A101200 + (ofs), mask, val)
#define CPSW_WR_M_G___(ofs, mask) REG32_M_G___(0x4A101200 + (ofs), mask)
#define CPSW_WR_M_S_WZ(ofs, mask, val) REG32_M_S_WZ(0x4A101200 + (ofs), mask, val)
代码中使用的关键寄存器:
| 偏移 | 寄存器名 | 功能说明 | 代码使用场景 |
|---|---|---|---|
| 0x14 | C0_RX_EN | Core0 RX中断使能。bit[7:0]每位对应一个RX通道 | 写bit0:仅使能RX通道0的中断到CPU |
| 0x1C | C0_MISC_EN | Core0 Misc中断使能。bit4=event, bit3=stat, bit2=host, bit1=mdio_link, bit0=mdio_user | 写bit1:仅使能MDIO链路变化中断 |
| 0x4C | C0_MISC_STAT | Core0 Misc中断状态(只读)。位定义同C0_MISC_EN | CpswWrMiscStatus():MISC ISR中读取,判断中断源 |
中断路由架构:
CPDMA/MDIO 中断源 CPSW_WR 路由 ARM INTC
┌─────────────────┐ ┌──────────────┐ ┌──────────────┐
│ RX CH0 完成 ├─────────►│ C0_RX_EN.b0 ├─────────►│ CPSW_RX_INT0 │
│ RX CH1 完成 │ ╳ │ C0_RX_EN.b1 │ │ │
│ ... │ │ ... │ │ │
├─────────────────┤ ├──────────────┤ ├──────────────┤
│ TX CH0 完成 │ ╳ │ C0_TX_EN.b0 │ │ CPSW_TX_INT0 │
│ ... │ │ ... │ │ │
├─────────────────┤ ├──────────────┤ ├──────────────┤
│ MDIO Link变化 ├─────────►│C0_MISC_EN.b1 ├─────────►│CPSW_MISC0_INT│
│ MDIO User完成 │ ╳ │C0_MISC_EN.b0 │ │ │
│ Host错误 │ ╳ │C0_MISC_EN.b2 │ │ │
│ Stat溢出 │ ╳ │C0_MISC_EN.b3 │ │ │
└─────────────────┘ └──────────────┘ └──────────────┘
╳ = 未使能(本驱动未使用)
2.9 CPSW_STATS — 统计寄存器 (0x4A100900)
功能概述:统计模块维护每个端口的以太网帧收发计数器,用于网络诊断和性能监控。读取后写回相同值可清零对应计数器。
宏定义:
#define CPSW_STATS___G___(ofs) REG32___G___(0x4A100900 + (ofs))
#define CPSW_STATS___S___(ofs, val) REG32___S___(0x4A100900 + (ofs), val)
统计寄存器映射(按 EthCpswStats 结构体顺序):
| 偏移 | 字段名 | 说明 | 诊断用途 |
|---|---|---|---|
| 0x04 | BroadcastRxFrames | 接收到的广播帧总数 | 广播风暴检测 |
| 0x08 | MulticastRxFrames | 接收到的多播帧总数 | 多播流量监控 |
| 0x0C | PauseRxFrames | 接收到的暂停帧数 | 流控诊断 |
| 0x10 | RxCrcErrors | CRC错误帧数 | 物理层/线缆质量 |
| 0x14 | RxAlignOrCodeErrors | 对齐/编码错误帧数 | 物理层/PHY问题 |
| 0x18 | OversizeRxFrames | 超大帧数 | MTU配置问题 |
| 0x1C | RxJabbers | Jabber帧数 | PHY硬件故障 |
| 0x20 | UndersizeRxFrames | 欠大小帧数 | 碰撞/截断 |
| 0x24 | RxFragments | 帧片段数 | 碰撞残留 |
| 0x28 | RxOctets | 接收总字节数 | 带宽统计 |
| 0x2C | GoodTxFrames | 发送的良好帧总数 | 基础发包计数 |
| 0x30 | BroadcastTxFrames | 发送的广播帧总数 | — |
| 0x34 | MulticastTxFrames | 发送的多播帧总数 | — |
| 0x38 | PauseTxFrames | 发送的暂停帧数 | 流控诊断 |
| 0x3C | DeferredTxFrames | 延迟发送帧数 | 半双工竞争 |
| 0x40 | Collisions | 碰撞总次数 | 半双工模式碰撞 |
| 0x44 | SingleCollisionTxFrames | 单次碰撞后成功帧数 | — |
| 0x48 | MultipleCollisionTxFrames | 多次碰撞后成功帧数 | — |
| 0x4C | ExcessiveCollisions | 因过度碰撞丢弃的帧数 | 严重碰撞问题 |
| 0x50 | LateCollisions | 因晚碰撞丢弃的帧数 | 线缆过长/双工不匹配 |
| 0x54 | TxUnderrun | 发送欠载数 | DMA/CPU性能不足 |
| 0x58 | CarrierSenseErrors | 载波侦测错误数 | 物理连接问题 |
| 0x5C | TxOctets | 发送总字节数 | 带宽统计 |
| 0x60 | RxTx0T64OctetFrames | 0~64字节帧数 | 帧长分布 |
| 0x64 | RxTx65T127OctetFrames | 65~127字节帧数 | — |
| 0x68 | RxTx128T255OctetFrames | 128~255字节帧数 | — |
| 0x6C | RxTx256T511OctetFrames | 256~511字节帧数 | — |
| 0x70 | RxTx512T1023OctetFrames | 512~1023字节帧数 | — |
| 0x74 | RxTx1024UpOctetFrames | 1024+字节帧数 | — |
| 0x78 | NetOctets | 收发总字节数 | 总带宽 |
| 0x7C | RxStartOfFrameOverruns | SOF溢出数 | CPDMA来不及处理 |
| 0x80 | RxMiddleofFrameOverruns | MOF溢出数 | CPDMA处理中溢出 |
| 0x84 | RxDmaOverruns | DMA溢出数 | 描述符耗尽 |
代码中特别关注的两个计数器:
#define CPSW_STAT_TX_UNDERRUN 0x54 // 发送欠载
#define CPSW_STAT_RX_UNDERRUN 0x84 // DMA溢出(代码中命名为RxUnderrun实为RxDmaOverruns)
// EthHwApi 提供给上层的接口:
uint32_t EthHwApi::CpswGetTxErrCount() → 读 0x54 并清零
uint32_t EthHwApi::CpswGetRxErrCount() → 读 0x84 并清零
2.10 CPPI RAM — 描述符内存 (0x4A102000)
功能概述:CPPI RAM是CPSW内部的8KB SRAM,专门用于存放DMA描述符(Buffer Descriptor)。描述符不能放在外部DDR中,必须位于此区域。实际的帧数据缓冲区则位于DDR中。
地址范围:0x4A102000 ~ 0x4A103FFF (8192字节)
宏定义:
#define AM335X_CPSW_CPPI_RAM_REGS (0x4A102000)
#define AM335X_CPSW_CPPI_RAM_SIZE (8192)
访问约束:只能32位对齐访问,不支持字节或半字访问。
内存布局(本驱动):
0x4A102000 ┌──────────────────────────────────────┐
│ TX 描述符区 (4096 字节) │
│ │
│ ┌── Port1 TX描述符 ──────────────────┐│
│ │ Desc[0]: NextDesc|Buf|BufLen|Flag ││ 每个描述符16字节
│ │ Desc[1]: ... ││ 共 CPSW_TX_DESC_NUMS/2 个
│ │ ... ││ = 4096/16/2 = 128 个
│ └────────────────────────────────────┘│
│ ┌── Port2 TX描述符 ──────────────────┐│
│ │ Desc[0]: NextDesc|Buf|BufLen|Flag ││
│ │ ... ││ 同样128个
│ └────────────────────────────────────┘│
0x4A103000 ├──────────────────────────────────────┤
│ RX 描述符区 (4096 字节) - 共享 │
│ │
│ ┌── 共享RX描述符链 ─────────────────┐ │
│ │ Desc[0] → Desc[1] → ... → Desc[N] │ │
│ │ ↓ NULL │ │ 共 256 个
│ └────────────────────────────────────┘│
0x4A103FFF └──────────────────────────────────────┘
描述符字段与硬件交互:
单个描述符 (EthDesc, 16字节):
+0 m_NextDesc ← CPU设置链表关系,DMA遍历
+4 m_Buf ← CPU设置,指向DDR中的数据缓冲区
+8 m_BufLenOrOfs ← CPU设置长度,DMA可能在RX时覆写
+12 m_DescFlag ← CPU和DMA都会读写
TX描述符标志位 (m_DescFlag):
bit31 SOP CPU设置 帧起始
bit30 EOP CPU设置 帧结束
bit29 Ownership CPU设置1→DMA清0 所有权转移
bit28 EOQ DMA设置 队列结束(用于追加检测)
bit20 To_Port_En CPU设置 定向发送使能
bit[17:16] To_Port CPU设置 目标端口(1=百兆, 2=千兆)
bit[10:0] Pkt_Len CPU设置 帧总长度
RX描述符标志位 (m_DescFlag):
bit31 SOP DMA设置 帧起始
bit30 EOP DMA设置 帧结束
bit29 Ownership CPU设置1→DMA清0 所有权转移
bit28 EOQ DMA设置 队列结束
bit[18:16] From_Port DMA设置 来源端口(1=百兆, 2=千兆)
bit[10:0] Pkt_Len DMA设置 帧总长度
2.11 Control Module — 引脚复用与系统控制 (0x44E10000)
功能概述:Control Module是AM335x的系统级配置模块,包含引脚复用(Pin Mux)、器件ID、安全控制、时钟控制等。以太网驱动中主要使用它的Pin Mux功能和GMII接口选择。
宏定义:
#define CTLM___S___(ofs, val) REG32___S___(0x44E10000 + (ofs), val)
#define CTLM_M_S___(ofs, mask, val) REG32_M_S___(0x44E10000 + (ofs), mask, val)
以太网相关关键寄存器:
| 偏移 | 寄存器名 | 功能说明 | 代码使用场景 |
|---|---|---|---|
| 0x800~0xB48 | CONF_xxx | 引脚复用配置(约200个) | Pin Mux初始化 |
GMII_SEL 寄存器 (偏移 0x650) 位域:
| 位 | 字段 | 说明 | 本驱动配置 |
|---|---|---|---|
| 3:2 | GMII2_SEL | Port2接口模式:同上 | 10 (RGMII) — 仅P4板 |
| 5 | RGMII2_IDMODE | Port2 RGMII内部延迟模式 | 1 — 仅P4板 |
| 6 | RMII1_IO_CLK_EN | Port1 RMII参考时钟来源:0=内部, 1=外部 | 1 (外部50MHz晶体) |
引脚复用寄存器通用格式:
所有 CONF_xxx 寄存器共用同一位域结构(参见引脚文档),通过 MuxApi::Init() 在启动时批量配置。以太网相关引脚的Mux配置在 kP1P2P3Cfgs[] 和 kP4Cfgs[] 数组中。
2.12 GPIO — 通用输入输出 (0x44E07000 / 0x4804C000 / 0x481AC000 / 0x481AE000)
功能概述:AM335x有4组GPIO(GPIO0~GPIO3),每组32个引脚。以太网驱动中GPIO用于PHY硬件复位、缓冲器控制和LED指示。
各Bank基地址:
| GPIO Bank | 基地址 | 以太网相关引脚 |
|---|---|---|
| GPIO1 | 0x4804C000 | GPIO1_16: CPU LED(非P4板), GPIO1_28: M3_RTCIn(P4板) |
| GPIO2 | 0x481AC000 | 未使用 |
| GPIO3 | 0x481AE000 | GPIO3_9: RGMII2缓冲器使能+RTL8211F复位, GPIO3_7: CPU LED(P4板) |
GPIO寄存器偏移(每个Bank内部相同):
| 偏移 | 寄存器名 | 功能 | 代码使用场景 |
|---|---|---|---|
| 0x138 | GPIO_DATAIN | 输入数据读取(只读) | Get():读取引脚电平 |
| 0x190 | GPIO_CLEARDATAOUT | 输出清零。写1清除对应位 | Clr():GPIO3_9拉低(复位PHY) |
| 0x194 | GPIO_SETDATAOUT | 输出置位。写1设置对应位 | Set():GPIO3_9拉高(释放复位) |
GPIO3_9 在千兆口初始化中的操作序列:
// 代码位于 EthGmiiSel() 中 port==2 分支
auto* pin = &s_EnableRgmii2Pin; // PintGp{3, 9} → GPIO3 Bank, Pin 9
pin->ConfigOutput(); // GPIO3_OE bit9 = 0 (设为输出)
pin->Clr(); // GPIO3_CLEARDATAOUT = _B(9) → 拉低
Gtc::MsDelay(20); // 保持20ms:复位PHY + 禁用缓冲器
pin->Set(); // GPIO3_SETDATAOUT = _B(9) → 拉高
Gtc::MsDelay(100); // 等待100ms:PHY从复位恢复
三、寄存器模块在数据收发中的协作关系
3.1 发送一帧数据的完整寄存器交互
用户调用 EthTx(dev, pbuf)
│
│ ① CPU操作 CPPI RAM (0x4A102000)
│ 填写TX描述符: NextDesc, Buf指针, BufLen, DescFlag
│ DescFlag = SOP|EOP|Ownership|To_Port_En|To_Port=port|PktLen
│
│ ② CPU写 STATERAM TX_HDP[ch] (0x4A100A00+ch*4)
│ 写入描述符地址,启动DMA发送
│
│ ③ CPDMA (0x4A100800) DMA引擎工作
│ 读取描述符 → 从DDR搬运帧数据 → 推入CPSW发送FIFO
│
│ ④ ALE (0x4A100D00) 地址查找
│ 根据To_Port定向发送 → 确定出口端口
│ 检查VLAN成员关系
│
│ ⑤ CPSW_SL (0x4A100D80/DC0) MAC层发送
│ 根据MACCONTROL寄存器的速度/双工设置
│ 通过RMII/RGMII物理接口发出帧
│
│ ⑥ CPDMA 完成
│ 清除描述符Ownership位
│ 如果是链尾,设置EOQ位
│ STATERAM TX_HDP[ch] 变为0
│
│ ⑦ STATS (0x4A100900) 更新
│ GoodTxFrames++, TxOctets+=帧长, ...
▼
3.2 接收一帧数据的完整寄存器交互
网线上有数据到达
│
│ ① PHY → CPSW_SL (0x4A100D80/DC0)
│ RMII/RGMII接口接收物理层数据
│ MAC层去除前导码、检查CRC
│
│ ② ALE (0x4A100D00) 地址查找
│ 提取目标MAC → 查找ALE表
│ 匹配VLAN单播条目 → 转发到P0(Host Port)
│ 填写From_Port字段
│
│ ③ CPDMA (0x4A100800) DMA引擎工作
│ 从发送FIFO取出帧数据
│ 查找CPPI RAM中Ownership=1的RX描述符
│ 将帧数据写入描述符指向的DDR缓冲区
│ 填写BufLen、DescFlag(SOP|EOP|From_Port|PktLen)
│ 清除Ownership位
│
│ ④ STATERAM RX_CP[0] (0x4A100A60) 更新
│ 指向最后完成的描述符
│
│ ⑤ CPSW_WR (0x4A101200) 中断路由
│ C0_RX_EN.bit0=1 → 触发CPSW_RX_INT0到ARM
│
│ ⑥ ARM INTC → EthCpswRxIsr
│ 读 RX_CP[0]
│ 调用 eth_device_ready() 通知协议栈
│ 写回 RX_CP[0] 确认
│ 写 CPDMA EOI_VECTOR = 1 (RX_PULSE)
│
│ ⑦ 协议栈线程调用 EthRx
│ 读取CPPI RAM描述符的From_Port字段
│ 分配pbuf,从DDR缓冲区拷贝数据
│ 回收描述符(重设Ownership=1,挂回链尾)
│ 如果EOQ被设置,重新写RX_HDP[0]重启接收
│
│ ⑧ STATS (0x4A100900) 更新
│ GoodRxFrames++, RxOctets+=帧长, ...
▼
3.3 PHY链路变化的完整寄存器交互
网线插入/拔出
│
│ ① PHY硬件检测到链路变化
│
│ ② MDIO (0x4A101000) 链路监控状态机
│ USERPHYSEL0/1 持续监控指定PHY地址的链路状态
│ 检测到变化 → 置位 LINKINTRAW.bit0 或 bit1
│
│ ③ CPSW_WR (0x4A101200) 中断路由
│ C0_MISC_EN.bit1=1 → 触发CPSW_MISC0_INT到ARM
│
│ ④ ARM INTC → EthCpswMiscIsr
│ 读 WR C0_MISC_STAT (0x4C) → 判断是MDIO_LINKINT
│ 读 MDIO LINKINTRAW (0x10) → 判断是哪个PHY
│ 清除 LINKINTRAW 对应位
│ 发送事件 EthPhyEventSend(port)
│ 写 CPDMA EOI_VECTOR = 3 (MISC_PULSE)
│
│ ⑤ PHY线程被事件唤醒
│ 通过 MDIO USERACCESS0 (0x80) 读取PHY寄存器:
│ BMSR (Reg 0x01) → 链路状态和自协商完成
│ GBSR (Reg 0x0A) → 千兆协商结果
│ ANLPAR (Reg 0x05) → 百兆协商结果
│
│ ⑥ 根据协商结果配置 CPSW_SL MACCONTROL (0x04)
│ 设置 GIG/IFCTL/GMII_EN/FULLDUPLEX 等位
│
│ ⑦ 通知协议栈 eth_device_linkchange(UP/DOWN)
▼
四、寄存器基地址完整汇总表
| 模块 | 基地址 | 大小 | 类别 | 数据流角色 | 初始化顺序 |
|---|---|---|---|---|---|
| GPIO0 | 0x44E07000 | 4KB | 系统 | 中断/通用IO | — |
| GPIO1 | 0x4804C000 | 4KB | 系统 | LED/M3_RTCIn | — |
| GPIO2 | 0x481AC000 | 4KB | 系统 | 未使用 | — |
| GPIO3 | 0x481AE000 | 4KB | 系统 | PHY复位/RGMII2缓冲器 | ① |
| CPSW_SS | 0x4A100000 | 256B | 交换 | 全局复位/统计使能 | ② |
| CPSW_PORT | 0x4A100100 | 768B | 交换 | 端口VLAN/MAC/FIFO配置 | ⑥ |
| CPDMA | 0x4A100800 | 256B | DMA | DMA引擎控制/中断/复位 | ④ |
| CPSW_STATS | 0x4A100900 | 144B | 统计 | 收发帧计数器(诊断用) | (运行时读取) |
| CPDMA_STATERAM | 0x4A100A00 | 128B | DMA | HDP/CP指针(启动/确认DMA) | ④ |
| CPPI RAM | 0x4A102000 | 8KB | DMA | 收发描述符存储 | ④ |
| CPSW_ALE | 0x4A100D00 | 128B | 交换 | 地址查找/VLAN/转发决策 | ⑤⑦ |
| CPSW_SL1 | 0x4A100D80 | 64B | MAC | 百兆口MAC层控制 | ⑥ |
| CPSW_SL2 | 0x4A100DC0 | 64B | MAC | 千兆口MAC层控制 | ⑥ |
| MDIO | 0x4A101000 | 256B | 管理 | PHY寄存器读写/链路监控 | ⑤ |
| CPSW_WR | 0x4A101200 | 256B | 中断 | 中断路由/使能/状态 | ③ |
初始化顺序编号对应 EthRegApi::Init() 中的调用顺序: ⓪ Pin Mux (MuxApi::Init) → ① GPIO (EthGmiiSel) → ② SS复位 → ③ WR复位 → ④ CPDMA复位(含CPPI RAM和STATERAM) → ⑤ MDIO复位+ALE初始化 → ⑥ SL复位+Port配置 → ⑦ ALE表项添加+MDIO PHY监控