PHY芯片 AR8033 学习笔记

【芯片简介】

AR8033是Atheros公司的第4代10/100/1000Mbps速率以太网PHY芯片,可用于家庭网关、企业交换机、移动基站、光模块等设备。该芯片采用RGMII协议或SGMII协议与MAC芯片进行通信,只需要单一3.3V电源供电,可自行整流变换出片内电路所需其它电源。AR8033还内置了一个工作频率为1.25GHz的SerDes接口,可以直接与光纤收发模块连接,将光信号转换为适用于1000BASE-X/100 BASE-FX传输模式的电信号或用于与MAC芯片通信的SGMII协议电信号。

PHY芯片在OSI协议栈中属于最底层的物理层,与其它层的关系图如下:

图1 PHY芯片的工作位置处于OSI底层

从硬件上来说,一般PHY芯片为模数混合电路,负责接收电、光这类模拟信号,经过解调和A/D转换后通过MII接口将信号交给MAC芯片进行处理。一般MAC芯片为纯数字电路。

【SerDes接口】

SerDes是SERializer(串行器)/DESerializer(解串器)的简称。它是一种主流的时分多路复用(TDM)、点对点(P2P)的串行通信技术,即在发送端多路低速并行信号被转换成高速串行信号,经过传输媒体(光缆或铜线),最后在接收端高速串行信号重新转换成低速并行信号。

【RGMII接口】

RGMII即Reduced GMII,是GMII的简化版本。它的接口信号线数量为14根(COL/CRS端口状态指示信号,这里没有画出),时钟频率为125MHz,TX/RX数据宽度为4位,为了保持1000Mbps的传输速率不变,RGMII接口在时钟的上升沿和下降沿都采样数据。在参考时钟的上升沿发送GMII接口中的TXD[3:0]/RXD[3:0],在参考时钟的下降沿发送GMII接口中的TXD[7:4]/RXD[7:4]。RGMII兼容100Mbps和10Mbps两种速率,此时参考时钟速率分别为25MHz和2.5MHz。

图2 RGMII接口

TX_EN信号线上传送TX_EN和TX_ER两种信息,在TX_CLK的上升沿发送TX_EN,下降沿发送TX_ER;同样的,RX_DV信号线上也传送RX_DV和RX_ER两种信息,在RX_CLK的上升沿发送RX_DV,下降沿发送RX_ER。

【SGMII接口】

SGMII即Serial GMII,是PHY与MAC之间的接口,时钟频率625MHz,收发各一对差分信号线,所以总的数据速率为1.25Gbps = 625Mbps* 2。GMII和RGMII都是并行的,而且需要随路时钟,PCB布线相对麻烦,不适于背板应用;而SGMII是串行的,不需要提供另外的时钟,MAC和PHY使用CDR来恢复时钟。参考时钟RX_CLK由PHY提供,是可选的,在时钟信号的上升沿和下降沿均发生采样,主要用于MAC侧没有时钟的情况,一般情况下,RX_CLK不使用,收发都可以从数据中恢复出时钟。

图3 SGMII接口图

在TXD发送的串行数据中,每8bits数据会插入TX_EN/TX_ER 的2bits控制信息,同样,在RXD接收数据中,每8bits数据会插入RX_DV/RX_ER 的2bits控制信息,称作8B/10B编码。

【MDC/MDIO接口】

接口有MDC和MDIO两条线。其中MDC上是由MAC提供的参考时钟信号,MDIO则是可双向传输的配置数据线,配合MDC时钟进行异步传输。AR8033的MDIO接口是开漏输出,所以在使用时需要外部上拉1.5k电阻。MDIO数据帧的组成如下:

图4 MDIO数据帧结构

各字段的含义如下:

PRE        对MDC时钟信号的回复,用于校正异步传输时钟,内容为32个数字1。

ST          数据帧开始标识。

OP          操作码,10表示读数据,01表示写数据。

PHYAD   PHY芯片的物理地址,共5位,其中3位可以在AR8033内部进行配置。

REGAD  寄存器地址,共5位,用于选中PHY芯片内的32个寄存器之一。

TA                 用于防止在数据传输期间建立新的连接,共2位。读操作期间第1位为高阻态,第2位为0;写操作期间第1位为1,第2位为0.

DATA     表示 从寄存器读到的数据 或 向寄存器写入的数据,共16位。从高位开始传输。

IDLE      帧间空闲信号,呈高阻态。相邻两个数据帧之间至少要有1个时钟的空闲信号。

【工作模式配置】

AR8033可以工作在3种模式类别下:电口模式、光口模式、光电转换器模式。根据4根模式选择引脚上电平的不同可以将AR8033配置到不同的工作模式。官方文档描述如下:

图5 模式选择引脚

图6 光口模式的引脚电平情况

从文档中可以看到,当我们希望AR8033工作在1000Mbps光口模式时,应该把RX_DV、RXD2、RX_CLK、RXD3这4个引脚的电平下拉和上拉为0010的情况。同理,要工作在100Mbps光口模式则可以将电平设置为0110或1110。

【应用示例】

我们可以使用AR8033对光口进行管理。根据官方数据手册描述,可以采用如下结构:

图7 AR8033光纤模块系统框图

从框图中可以看出,当AR8033芯片用于光纤模块管理时,需要配置成100BASE-FX模式或1000BASE-X模式,与交换机芯片之间的数据传输采用RGMII协议。实际应用时,AR8033的工作模式直接由主控芯片通过MDC/MDIO总线进行配置;数据传输路径是AR8033传递给交换芯片,再由交换芯片传递给主控芯片。示意图如下:

图8 AR8033应用示意图

在示意图中可以看到,光模块芯片AR8033与交换芯片之间的数据传输使用RGMII协议,交换芯片与主控芯片之间的数据传输使用SGMII协议。

【代码分析】

想要在Linux上使用AR8033需要做2部分工作,一是编写设备驱动并将设备驱动注册到内核,二是创建设备通信要使用的mdio总线并将设备注册到总线上。

a)  驱动注册流程:

文件mdio_gpio.c 是 mdio_gpio 模块的代码所在。在模块加载函数 mdio_gpio_init() 中通过语句 ret = platform_driver_register(&mdio_gpio_driver) 将mdio 驱动注册为“平台设备驱动”,其中mdio_gpio_driver 是一个 platform_driver 结构体,初始化代码如下:

static struct platform_driver mdio_gpio_driver= {

.probe= mdio_gpio_probe,    // 关联设备的probe函数

.remove= __devexit_p(mdio_gpio_remove),    // 关联设备的remove函数

.driver            = {

.name      = "mdio-gpio",    // 驱动名

.owner    = THIS_MODULE,

},

};

而在 platform_driver_register() 这个函数中,则进一步将驱动总线类型设定为 platform_bus_type,以及关联驱动的probe()函数、remove()函数和shutdown()函数。其代码细节如下:

int platform_driver_register(structplatform_driver *drv)

{

drv->driver.bus= &platform_bus_type;

if(drv->probe)

drv->driver.probe = platform_drv_probe;    //
注意,这是drv->driver.probe

if(drv->remove)

drv->driver.remove= platform_drv_remove;    // 关联drv->driver.remove

if(drv->shutdown)

drv->driver.shutdown= platform_drv_shutdown;    // 关联drv->driver.shutdown

returndriver_register(&drv->driver);

}

可以看到,对于所有驱动而言初始化到这一步时都会指向probe()、remove()、shutdown()这3个函数,这3个函数分别用来返回“平台设备驱动”的probe()、remove()、shutdown()函数。代码如下:

static int platform_drv_probe(struct device*_dev)

{

structplatform_driver *drv = to_platform_driver(_dev->driver);

structplatform_device *dev = to_platform_device(_dev);

returndrv->probe(dev);

}

而在platform_driver_register()函数结尾的 return 语句中,再调用driver_register(&drv->driver) 进一步对驱动进行注册。通过语句driver_find(drv->name, drv->bus)查找总线上是否已经注册过该驱动,若没有则使用语句bus_add_driver(drv) 将驱动添加到总线中。至此,驱动注册流程结束。代码如下:

int driver_register(struct device_driver*drv)

{

intret;

structdevice_driver *other;

BUG_ON(!drv->bus->p);    // 打开调试

// 做一些检测

if((drv->bus->probe && drv->probe) ||

(drv->bus->remove &&drv->remove) ||

(drv->bus->shutdown &&drv->shutdown))

printk(KERN_WARNING"Driver ‘%s‘ needs updating - please use "

"bus_typemethods\n", drv->name);

other = driver_find(drv->name, drv->bus);    //
在总线中查找是否已经注册该驱动

if(other) {

printk(KERN_ERR"Error: Driver ‘%s‘ is already registered, "

"aborting...\n",drv->name);

return-EBUSY;

}

ret = bus_add_driver(drv);   // 将驱动添加到总线

if(ret)

returnret;

ret= driver_add_groups(drv, drv->groups);

if(ret)

bus_remove_driver(drv);

returnret;

}

b)  设备注册流程:

驱动注册流程的末尾会调用驱动的 probe() 函数,即 mdio_gpio_probe() 函数。在该函数中,通过语句new_bus = mdio_gpio_bus_init(&pdev->dev, pdata,pdev->id) 初始化一个 mdio 总线设备,在使用语句 mdiobus_register(new_bus)对该设备总线进行注册。代码如下:

static int __devinit mdio_gpio_probe(structplatform_device *pdev)

{

structmdio_gpio_platform_data *pdata = pdev->dev.platform_data;

structmii_bus *new_bus;

intret;

if(!pdata)

return-ENODEV;

new_bus = mdio_gpio_bus_init(&pdev->dev, pdata,pdev->id);

if(!new_bus)

return-ENODEV;

ret = mdiobus_register(new_bus);

if(ret)

mdio_gpio_bus_deinit(&pdev->dev);

returnret;

}

进入函数 mdiobus_register() 查看代码,内容可以分为2部分。一是对 mdio 总线设备进行真正的注册,二是注册成功后,在总线上根据 phy_mask搜索 PHY 设备。代码如下:

int mdiobus_register(struct mii_bus *bus)

{

inti, err;

if(NULL == bus || NULL == bus->name ||

NULL== bus->read ||

NULL== bus->write)

return-EINVAL;

BUG_ON(bus->state!= MDIOBUS_ALLOCATED &&

bus->state != MDIOBUS_UNREGISTERED);

bus->dev.parent= bus->parent;

bus->dev.class= &mdio_bus_class;

bus->dev.groups= NULL;

dev_set_name(&bus->dev,"%s", bus->id);

err = device_register(&bus->dev);    //
注册 mdio总线设备

if(err) {

printk(KERN_ERR"mii_bus %s failed to register\n", bus->id);

return-EINVAL;

}

mutex_init(&bus->mdio_lock);

if(bus->reset)

bus->reset(bus);

for(i = 0; i < PHY_MAX_ADDR; i++) {

if((bus->phy_mask & (1 << i)) == 0) {

structphy_device *phydev;

phydev = mdiobus_scan(bus, i);    //
在总线上搜索 phy 设备

if(IS_ERR(phydev)) {

err= PTR_ERR(phydev);

gotoerror;

}

}

}

bus->state= MDIOBUS_REGISTERED;

…   // 以下省略

}

进入函数 mdiobus_scan() 查看代码,可以看到在该函数中使用 phydev = get_phy_device(bus, addr) 语句从总线设备上获取到 phy 设备,然后通过语句phy_device_register(phydev) 对phy 设备进行注册。至此,设备注册流程结束。代码如下:

struct phy_device *mdiobus_scan(structmii_bus *bus, int addr)

{

structphy_device *phydev;

structmdio_board_entry *be;

interr;

phydev = get_phy_device(bus, addr);    //
从总线设备上获取 phy 设备

if(IS_ERR(phydev) || phydev == NULL)

returnphydev;

mutex_lock(&__mdio_board_lock);

list_for_each_entry(be,&__mdio_board_list, list)

mdiobus_setup_phydev_from_boardinfo(bus,phydev,

&be->board_info);

mutex_unlock(&__mdio_board_lock);

err = phy_device_register(phydev);    //
将 phy 设备注册到内核

if(err) {

phy_device_free(phydev);

returnNULL;

}

returnphydev;

}

时间: 2024-10-25 02:35:24

PHY芯片 AR8033 学习笔记的相关文章

树莓派学习笔记——Model B Model B+ Compute Module Dev Kit的区别和联系

0 前言 最近浏览器树莓派官方发现树莓派推出了两款新Model--一款名为树莓派 model B+,一款名为树莓派 Compute Module Dev Kit.带着欣喜和恐惧查阅了相关资料,并通过淘宝和RS中国了解开发板价格.欣喜的感觉来自于树莓派的功能得到了增强,恐惧来自于树莓派的改变带来新的学习成本.经过几天的资料收集,所以整理成博文和大家分享. 1 横向比较 [共性比较] 表1 三款树莓派横向比较 区别 Model B Model B+ Compute Module Dev Kit 芯片

义隆单片机学习笔记之(四) 编程及烧录

工具说明: 1.UIDE,编程环境 2.UWriter:烧录软件 下载地址: (见官网) 一 UIDE  1.1 创建工程: 1.2 选择型号: 1.3 编程及编译 二 UWriter 2.1 安装 (Serial number在购买烧录器的时候,从代理经销商处获得!) 2.2 选择目标芯片  2.3 配置选择 (注:由于是OTP,很多功能都是在配置的时候指定,所以这里非常重要.晶振.时钟的选择,延时程序要与之对应: 是否需要保护等,根据自己的需要而定) 编译之后生成的.map文件,详细的描述了

程序员的自我修养 学习笔记(1)

本文源自在学习<程序员的自我修养>中的心得体会. 对于底层系统程序开发者来说,硬件平台可以抽象为三个主要部件,CPU.内存.I/O控制器. 早期的计算机没有复杂的图形功能,CPU和内存之间的频率差异不大,它们都是连接在同一个bus上面的.其他I/O设备,诸如显示设备.键盘.磁盘等速度比内存.CPU慢很多.为了IO设备与CPU.内存之间的协调通讯,一般每个IO设备商都有相应的IO控制器,早期的硬件结构图如下: 随着技术的进步,CPU的频率越来越高,内存跟不上CPU的速度,他们之间就需要一个转换机

C51学习笔记

转自:http://blog.csdn.net/gongyuan073/article/details/7856878 单片机C51学习笔记 一,   C51内存结构深度剖析 二,   reg51.头文件剖析 三,   浅淡变量类型及其作用域 四,   C51常用头文件 五,   浅谈中断 六,   C51编译器的限制 七,                        小淡C51指针 八,                        预处理命令                        

[51单片机学习笔记TWO]----蜂鸣器

蜂鸣器音乐播放实验 首先应该了解一下蜂鸣器音乐播放的原理,在这里我只讲一下电磁式蜂鸣器驱动原理(还有一种是压电式蜂鸣器): 电磁式蜂鸣器驱动原理: 蜂鸣器发声原理是电流通过电磁线圈,使电磁圈产生磁场来驱动振动膜发声的.因此需要一定的电流才能驱动它,而单片机I/O引脚输出的电压较小.单片机输出的TTLK电平基本驱动不了蜂鸣器,因需要增加一个放大电路.这里用三极管作为放大电路.下面是原理图: 我这里的J8端是跟芯片的P1^5端口相连,当P1^5输出高电平时,三极管截止,蜂鸣器不发声,反之,输出低电平

AM335x(TQ335x)学习笔记——触摸屏驱动编写

前面几篇文章已经通过配置DTS的方式完成了多个驱动的移植,接下来我们解决TQ335x的触摸驱动问题.由于种种原因,TQ335x的触摸屏驱动是以模块方式提供的,且Linux官方内核中也没有带该触摸屏的驱动源码,单纯的配置DTS是无法完成TQ335x的触摸驱动移植工作的,因此,本文参考内核中原有的pixcir_i2c_ts驱动编写TQ335x的触摸屏(TN92)驱动. 在之前移植TQ210时,我已经编写过TQ210的触摸屏驱动,我的TQ335x还是使用的TQ210的屏,因此,难度不是很大.这里需要说

树莓派学习笔记——USB wifi配置指南

0 前言 树莓派既可以使用有线网络又可以无线网络,如果使用有线网络不方便的话可以借助USB wifi无线网卡让树莓派也插上无线"翅膀".但是和使用有线网络即插即用的方式不同,USB wifi网卡需要进行一些配置.通过一天的配置实验,本文总结了树莓派wifi配置的两种方法--[1]使用wpa_gui工具方法和[2]修改配置文件方法. [1]使用wpa_gui工具方法 wpa_gui是一种linux平台常用的wifi配置工具,wpa_gui具有图形界面操作简单.由于,树莓派B板只有两个US

linux内存操作--ioremap和mmap学习笔记

最近在做视频输出相关的东西,对于预留给framebuffer的内存使用不是很清楚,现在找到一些资料整理一下,以备使用. 对于一个系统来讲,会有很多的外设,那么这些外设的管理都是通过CPU完成.那么CPU在这个过程中是如何找到外设的呢? 尽管在一个系统中会有诸多的外设,在每个外设的接口电路中会有多个端口.但是如果系统能够每个端口都被赋予一个具体的地址值,那么在系统中就能轻易的找到任何一个外设.系统在管理的时候,不管是内存还是外设都需要分配一个内存地址.对于一个32bit的系统来讲,可寻址的范围为2

树莓派学习笔记——Wifi AP热点模式 使用RT5370

0.前言 本文详细说明为树莓派增加Wifi AP热点功能的具体步骤.配置完成之后,树莓派将增加一个Wifi热点功能,使用笔记本或手机便可连接树莓派,树莓派具有了AP热点功能,可更一步扩展树莓派相关的WEB功能,通过连接树莓派提供的热点,登录树莓派提供的WEB服务,便可获得树莓派所监控的相关信息. 配置的步骤较多,请保持耐心. [配置说明] 1.树莓派热点名称(SSID)为Raspberry_AP,热点密码为12345678,加密方式为WPA2. 2.树莓派无线网口的IP地址为192.168.0.