MDIO接口包括两根信号线:MDC和MDIO,通过它,MAC层芯片(或其它控制芯片)可以访问物理层芯片的寄存器,并通过这些寄存器来对物理层芯片进行控制和管理。
驱动MDIO的设备称为STA(Station Management Entity),MDIO控制的目标设备称为MMD(MDIO Manageable Devices),我们的jupiter芯片就是MMD。
MDIO管理接 口如下:
MDC:管理接口的时钟,它是一个非周期信号,信号的最小周期(实际是正电平时间和负电平时间之和)为400ns,最小正电平时间和负电平时间为160ns,最大的正负电平时间无限制。它与TX_CLK和RX_CLK无任何关系。
MDIO是一根双向的数据线。用来传送MAC层的控制信息和物理层的状态信息。MDIO数据与MDC时钟同步,在MDC上升沿有效。
MDIO clause 22管理接口的数据帧结构如:
图1 clause 22数据帧结构
ST |
2bit固定为01 |
OP |
读指令10,写指令01 |
PHYADR |
5bit 物理设备地址 |
REGADR |
5bit寄存器地址 |
TA |
2bit反转位,写指令时由STA写入10,读指令时由MMD返回Z0 |
DATA |
16bit,写指令时同STA写入的内容;读指令时由MMD返回的内容 |
图3 clause 45数据帧结构
ST |
2bit固定为00 |
OP |
OP code |
PHYADR |
5bit 物理设备地址 |
DEVTYPE |
5bit设备类型 |
TA |
2bit反转位,写指令时由STA写入10,读指令时由MMD返回Z0 |
ADDR/DATA |
16bit,地址或数据 |
相对于clause 22,clause 45最大的改变是如何操作寄存器。在clause 22中一个数据帧就可以完成某个寄存器的读写,但在clause 45中需要两个数据帧,第一个帧指定需要操作的寄存器地址,第二个为具体操作的内容,clause 45中00的OP code就是指定寄存器地址的数据帧。在clause45中,寄存器地址可以有16位,即65536个。
OP code10为 READ+Addr,和Read指令有点类似,但读取后会自动将原有的寄存器地址加1,非常适用于调试状态下读取所有寄存器的操作。
我们的Jupiter芯片来讲,设定了PHYADR和DEVTYPE均为0,通过16位的寄存器地址来区分。在操作MMD前还需要发送32位1。
MPC8548 使用一组MII 寄存器完成MDIO/MDC,所有MDIO/MDC的协议细节均由芯片自动完成,如下是网卡驱动的代码片断:
struct gfar_mii {
u32 miimcfg; /*0x.520 - MII Management Config Register */
u32 miimcom; /*0x.524 - MII Management Command Register */
u32 miimadd; /*0x.528 - MII Management Address Register */
u32 miimcon; /*0x.52c - MII Management Control Register */
u32 miimstat; /*0x.530 - MII Management Status Register */
u32 miimind; /*0x.534 - MII Management Indicator Register */
};
1. miimcfg,在MPC8548 datasheet 中也是如下名字(下同),主要用来Reset 和设置时钟频率
2. miimcom,用来设置读标志位
3. miimadd,设置MDIO 22中的phyaddr和regaddr,各5位,一共10位
4. miimcon,写操作的16位数据
5. miimstat,读操作的数据返回
6. miimind,标志寄存器,表示正忙或者是否有效
读流程
1. 设置miimadd,写入phyaddr和regaddr
2. 设置miimcom的读标志位,注意必有将其设置为0到1的转换才能触发读操作
3. 循环读取miimind,等待读取操作完成(BUSY标志清0)并且有效(Not valid标志清0)
4. 读取miimstat,其中就有16位结果
写流程
1. 设置miimadd,写入phyaddr和regaddr
2. 设置miimcon,写入16位数据触发写操作
3. 循环读取miimind,等待写入操作完成(BUSY标志清0)
MPC8548的MDIO无法支持Clause 45,故只能使用GPIO模拟MDIO
GPIO控制寄存器。设置哪些pin 脚作为GPIO 输入、输出使用,以下内容取自MBC8548datasheet,寄存器偏移地址 0xe_0030
Bit 位 |
名称 |
含义 |
6 |
Tx2out |
使能TSEC2_TX[7:0]作为GPIO 的output |
7 |
Rx2in |
使能TSEC2_RX[7:0]作为GPIO 的input |
14 |
PCIout |
使能PCI2_AD[15:8]作为GPIO 的output |
15 |
PCIin |
使能PCI2_AD[7:0]作为GPIO 的input |
22 |
GPout |
使能GPOUT[31:24]作为GPIO 的output |
GPIO output data寄存器,gpio写入时使用,每一位代表一个pin脚,将需要写入的bit值写到该寄存器对应的位即可
Bit 位 |
名称 |
含义 |
0 |
TSEC2_TXD[7] |
|
1 |
TSEC2_TXD[6] |
|
2 |
TSEC2_TXD[5] |
|
3 |
TSEC2_TXD[4] |
|
4 |
TSEC2_TXD[3] |
|
5 |
TSEC2_TXD[2] |
|
6 |
TSEC2_TXD[1] |
|
7 |
TSEC2_TXD[0] |
|
8 |
PCI2_AD[15] |
|
9 |
PCI2_AD[14] |
|
10 |
PCI2_AD[13] |
|
11 |
PCI2_AD[12] |
|
12 |
PCI2_AD[11] |
|
13 |
PCI2_AD[10] |
|
14 |
PCI2_AD[9] |
|
15 |
PCI2_AD[8] |
|
24 |
GPOUT[24] |
|
25 |
GPOUT[25] |
|
26 |
GPOUT[26] |
|
27 |
GPOUT[27] |
|
28 |
GPOUT[28] |
|
29 |
GPOUT[29] |
|
30 |
GPOUT[30] |
|
31 |
GPOUT[31] |
|
GPIO IN data寄存器,gpio读取时使用,每一位代表一个pin脚,将需要写入的bit值写到该寄存器对应的位即可
Bit 位 |
名称 |
含义 |
0 |
TSEC2_RXD[7] |
|
1 |
TSEC2_RXD[6] |
|
3 |
TSEC2_RXD[4] |
|
4 |
TSEC2_RXD[3] |
|
5 |
TSEC2_RXD[2] |
|
6 |
TSEC2_RXD[1] |
|
7 |
TSEC2_RXD[0] |
|
8 |
PCI2_AD[7] |
|
9 |
PCI2_AD[6] |
|
10 |
PCI2_AD[5] |
|
11 |
PCI2_AD[4] |
|
12 |
PCI2_AD[3] |
|
13 |
PCI2_AD[2] |
|
14 |
PCI2_AD[1] |
|
15 |
PCI2_AD[0] |
|
MPC8548的某个GPIO pin要么是输入、要么是输出,不能配置为双向,而MDIO为双向数据线,因此需要两个GPIO(一个OUT、一个IN)来模拟MDIO,一个GPIO OUT来模拟MDC
TSEC2_TX[7] 模拟MDC
TSEC2_RX[7] 模拟MDIO的input
PCI2_AD[8] 模拟MDIO的output
TSEC2_TX[7]直接接到芯片的MDC,TSEC2_RX[7]、GPOUT[31]共同接到芯片的MDIO
1. 写指令
使能TSEC2_TX、PCI2_AD,禁用TSEC2_RX;按照MDIO/MDC规范写入数据
2. 读数据
使用TSEC2_TX、TSEC2_RX,禁用PCI2_AD;按照MDIO/MDC规范读取数据
GPIO模拟MDIO/MDC时,必须一个bit一个bit的发送指令,参考linux kernel原有的mdio-bitbang.c,改写成支持clause 45的格式。
MDIO 协议和硬件实现分离,分为MDIO协议模块、GPIO模块、应用层模块共三个子模块。
MDIO协议模块和硬件实现无关,单纯的协议操作,涉及硬件的部分使用接口隐藏,由GPIO模块提供硬件操作函数。
GPIO 模块提供硬件操作函数,应用层接口函数(使用proc文件系统)
应用层模块提供统一的寄存器读写接口函数。
struct mdiobb_ops {
/* Set the Management Data Clock highif level is one,
* low if level is zero.
*/
void (*set_mdc)(struct mdiobb_ops *ops,int level);
/* Configure the Management Data I/Opin as an input if
* "output" is zero, or an output if"output" is one.
*/
void (*set_mdio_dir)(struct mdiobb_ops*ops, int output);
/* Set the Management Data I/O pin highif value is one,
* low if "value" is zero. This may only be called
* when the MDIO pin is configured as anoutput.
*/
void (*set_mdio_data)(struct mdiobb_ops*ops, int value);
/* Retrieve the state Management DataI/O pin. */
int (*get_mdio_data)(struct mdiobb_ops*ops);
};
set_mdc,发送MDC 信号的函数,由具体硬件寄存器决定
set_mdio_dir,设置MDIO方向的函数,由具体硬件寄存器决定
set_mdio_data,发送MDIO数据到MMD,由具体硬件寄存器决定
get_mdio_data,从MMD接收MDIO数据,由具体硬件寄存器决定
注意以上函数均以bit 为单位进行,此结构由MDIO协议模块使用,由gpio模块定义。
structgpio_mdio45_info {
struct mdiobb_ops ops;
struct gpio_reg *regs;
spinlock_t lock;
#defineADDR_TO_PHY(x) ((x)>>24)
#defineADDR_TO_DEV(x) (((x)>>16) & 0xff)
#defineADDR_TO_REG(x) ((x) & 0xffff)
unsigned int addr; /* phyaddr(8bit) + devtype(8bit) +regaddr(16bit) */
/* proc element */
struct proc_dir_entry *dir;
struct proc_dir_entry *addr_entry;
struct proc_dir_entry *read_entry;
struct proc_dir_entry *write_entry;
};
此结构由gpio模块定义并使用。
ops, 用于MDIO协议模块
regs, GPIO硬件地址
lock, 互斥锁,确保MDIO读写操作的完整性
addr, 应用层下发的地址结构,有三部分组成,寄存器读写时必须使用该地址
proc... proc相关,定义了三个文件,
addr为可读可写文件,表示地址结构,和addr完全对应
read为只读文件,读取该文件时触发MDIO读操作
write为只写文件,写入该文件时触发MDIO写操作
对应文件mdio45_bitbang.c,其中最关键的两个函数实现是发送1bit和接收1bit。由于需要通过GPIO模拟MDIO,在发送1bit数据时,首先产生1bit数据,然后设置MDC由1到0的反转,如此就将1bit数据发送成功了。
读取1bit数据时,先设置MDC由1到0的反转,然后再读取数据。
可以简单的认为,MDC由1到0的反转会触发MMD的动作。
注意设置MDC时需要延时,具体数值需要参考MDIO/MDC协议。
首先需要熟悉MPC8548 GPIO 的所有GPIO寄存器,在操作GPIO寄存器之前需要作ioremap内存地址映射,将I/O地址映射为内存地址可以方便的操作。
具体在写寄存器时需要先读取、再写入。
利用proc文件系统实现Linux内核层、应用层的数据交互。如此可以方便的进行测试,在不写应用层程序时也能测试。
主目录为/proc/gpio-mdio45/,其中定义了三个文件,
addr为可读可写文件,表示地址结构,和addr完全对应
read为只读文件,读取该文件时触发MDIO读操作
write为只写文件,写入该文件时触发MDIO写操作
这三个文件的内容均为16进制字符串,以0x开头的数据形式。