[patch]Add the MII core
网卡驱动开发,所涉及到的主要内容就是对EMAC和PHY的操作,EMAC和PHY通过MII接口进行通信,通过对比DM9000和AT91SAM9263网卡驱动我们可以发现,
不管EMAC和PHY是集成的还是外接的,PHY对外提供的接口(MII register)是一致的,所不同的只是EMAC对PHY操作方法,因此,可以在g-bios中抽象出一层
MII CORE层,MII CORE层封装了一些基本的PHY操作,比如reset phy, power off phy,get link status等,驱动层只要把操作PHY寄存器的具体方法作为函
数指针传递给MII CORE层的数据结构,就无须关心PHY内部的实现。
signed-off-by: Jack Jiang <voidjack.jiang@gmail.com>
--------------------------------------------------------------------------------------------------------
From 4245fe23e3d491af2dbe81ef17a1bfcda1c497e3 Mon Sep 17 00:00:00 2001
From: Jack Jiang <voidjack.jiang@gmail.com>
Date: Mon, 16 Nov 2009 23:16:18 +0800
Subject: [PATCH 1/2] Add mii core
---
device/net/Makefile | 2 +-
device/net/mii_core.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++
include/net/mii.h | 32 ++++++++++++-
3 files changed, 155 insertions(+), 2 deletions(-)
create mode 100644 device/net/mii_core.c
diff --git a/device/net/Makefile b/device/net/Makefile
index 88b5c83..548e6c7 100644
--- a/device/net/Makefile
+++ b/device/net/Makefile
@@ -3,7 +3,7 @@ obj-$(CONF_DM9000) += dm9000.o
obj-$(CONF_CS8900) += cs8900.o
obj-$(CONF_AT91SAM9263) += eth_at91.o
-OBJS_C = tftp.o net_core.o socket.o $(obj-y)
+OBJS_C = tftp.o net_core.o socket.o mii_core.o $(obj-y)
SRCS_C := $(OBJS_C:.o=.c)
all: $(BUILT_IN_OBJ)
diff --git a/device/net/mii_core.c b/device/net/mii_core.c
new file mode 100644
index 0000000..708fd89
--- /dev/null
+++ b/device/net/mii_core.c
@@ -0,0 +1,123 @@
+#include <stdio.h>
+#include <malloc.h>
+#include <core/errno.h>
+#include <net/net.h>
+#include <net/mii.h>
+
+#define TIME_OUT 100
+
+static struct PhyDevice *g_PhyDev;
+
+static unsigned short GkPhyGetPhyAddr(struct PhyDevice *pPhyDev)
+{
+ BYTE bPhyIndex;
+
+ for (bPhyIndex = 0; bPhyIndex < MAX_PHY_NUM; bPhyIndex++)
+ {
+ if (PHY_ID1 == pPhyDev->PhyRead(bPhyIndex, MII_REG_ID1))
+ {
+ printf("Find the active PHY, PHY index is %d\n", bPhyIndex);
+
+ return bPhyIndex;
+ }
+ }
+
+ printf("Can't find active PHY!\n");
+
+ return -EIO;
+}
+
+struct PhyDevice *GkPhyDevNew(void)
+{
+ struct PhyDevice *pPhyDev;
+
+ pPhyDev = (struct PhyDevice *)zalloc(sizeof(*pPhyDev));
+ if (!pPhyDev)
+ {
+ printf("Alloc PhyDev failed!\n");
+ return NULL;
+ }
+
+ return pPhyDev;
+}
+
+int GkPhyDevRegister(struct PhyDevice *pPhyDev)
+{
+ BYTE bPhyIndex;
+
+ if (!pPhyDev->PhyRead || !pPhyDev->PhyWrite)
+ {
+ return -EINVAL;
+ }
+
+ bPhyIndex = GkPhyGetPhyAddr(pPhyDev);
+ if (bPhyIndex < 0)
+ {
+ return -EIO;
+ }
+
+ pPhyDev->bPhyIndex = bPhyIndex;
+
+ g_PhyDev = pPhyDev;
+
+ return 0;
+}
+
+int GkPhyResetPhy(void)
+{
+ g_PhyDev->PhyWrite(MII_PHY_RESET, g_PhyDev->bPhyIndex, MII_REG_BMC);
+
+ while (g_PhyDev->PhyRead(g_PhyDev->bPhyIndex, MII_REG_BMC) & MII_PHY_RESET);
+
+ printf("Phy reset OK!\n");
+
+ return 0;
+}
+
+int GkPhyClosePhy(void)
+{
+ g_PhyDev->PhyWrite(MII_PHY_POWERDOWN, g_PhyDev->bPhyIndex, MII_REG_BMC);
+}
+
+int GkPhyGetLinkStatus(void)
+{
+ int iTimeOut;
+
+ for (iTimeOut = 0; iTimeOut < TIME_OUT; iTimeOut++)
+ {
+ if (g_PhyDev->PhyRead(g_PhyDev->bPhyIndex, MII_REG_BMS) & MII_PHY_AUTONEG_COMP)
+ {
+ printf("Auto-negotiation complete!\n");
+ goto L1;
+ }
+ udelay(100000);
+ }
+
+ if (TIME_OUT == iTimeOut)
+ {
+ printf("Time out, Auto-negotiation failed!\n");
+ return -EIO;
+ }
+
+L1:
+ switch (g_PhyDev->PhyRead(g_PhyDev->bPhyIndex, MII_REG_STAT) >> 12)
+ {
+ case 1:
+ return ETHER_SPEED_10M_HD;
+
+ case 2:
+ return ETHER_SPEED_10M_FD;
+
+ case 4:
+ return ETHER_SPEED_100M_HD;
+
+ case 8:
+ return ETHER_SPEED_100M_FD;
+
+ default:
+ break;
+ }
+
+ return ETHER_SPEED_UNKNOW;
+}
+
diff --git a/include/net/mii.h b/include/net/mii.h
index 7838353..0c30eac 100644
--- a/include/net/mii.h
+++ b/include/net/mii.h
@@ -13,5 +13,35 @@
#define MII_REG_ESTATUS 0x0f
#endif
-#define MII_PHY_RESET 0x8000
+#define MII_REG_DSC 16
+#define MII_REG_STAT 17
+
+#define MII_PHY_RESET 1 << 15
+#define MII_PHY_POWERDOWN 1 << 11
+#define MII_PHY_ENABLE_AUTONEG 1 << 12
+#define MII_PHY_RESTART_AUTONEG 1 << 9
+#define MII_PHY_AUTONEG_COMP 1 << 5
+
+#define MAX_PHY_NUM 32
+#define PHY_REG_NUM 32
+
+#define PHY_ID1 0x181 //fix me, should be from the autoconf.h
+#define PHY_ID2
+
+struct PhyDevice
+{
+ BYTE bPhyIndex;
+ unsigned short (*PhyRead)(BYTE bPhyAddr, BYTE bPhyRegIndex);
+ void (*PhyWrite)(unsigned short hVal, BYTE bPhyAddr, BYTE bPhyRegIndex);
+};
+
+struct PhyDevice *GkPhyDevNew(void);
+
+int GkPhyDevRegister(struct PhyDevice *pPhyDev);
+
+int GkPhyResetPhy(void);
+
+int GkPhyClosePhy(void);
+
+int GkPhyGetLinkStatus(void);
--
1.6.3.3
[ 本帖最后由 voidjackjiang 于 2009-11-17 10:55 编辑 ]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
g-bios添加了MII CORE层后,修改了DM9000E网卡驱动相关代码。
signed-off-by: voidjackjiang <voidjack@163.com>
--------------------------------------------------------------------------------------
From ebcc33a032664ffb5bd955ad574e15efec4e62c6 Mon Sep 17 00:00:00 2001
From: Jack Jiang <voidjack.jiang@gmail.com>
Date: Mon, 16 Nov 2009 23:55:22 +0800
Subject: [PATCH 2/2] Add mii function for DM9000E
---
device/net/dm9000.c | 68 ++++++++++++++++----------------------------------
1 files changed, 22 insertions(+), 46 deletions(-)
diff --git a/device/net/dm9000.c b/device/net/dm9000.c
index fd884d7..8ed4fec 100644
--- a/device/net/dm9000.c
+++ b/device/net/dm9000.c
@@ -15,9 +15,6 @@
#include "dm9000.h"
-static int DM9000GetLinkStatus(void);
-
-
static BYTE DM9000Read(BYTE bRegIdx)
{
WriteByte(bRegIdx, DM9000_INDEX_PORT);
@@ -32,11 +29,11 @@ static void DM9000Write(BYTE bRegIdx, BYTE bValue)
}
-static UINT16 DM9000PhyRead(BYTE bRegIdx)
+static UINT16 DM9000PhyRead(BYTE bPhyAddr, BYTE bRegIdx)
{
UINT16 hVal;
- DM9000Write(DM9000_EPAR, DM9000_PHY_INTER | bRegIdx);
+ DM9000Write(DM9000_EPAR, bPhyAddr << 6 | bRegIdx);
DM9000Write(DM9000_EPCR, DM9000_PHY_SELECT | DM9000_PHY_READ);
while (DM9000Read(DM9000_EPCR) & DM9000_PHY_BUSY);
@@ -49,9 +46,9 @@ static UINT16 DM9000PhyRead(BYTE bRegIdx)
}
-static void DM9000PhyWrite(BYTE bRegIdx, UINT16 hVal)
+static void DM9000PhyWrite(UINT16 hVal, BYTE bPhyAddr, BYTE bRegIdx)
{
- DM9000Write(DM9000_EPAR, DM9000_PHY_INTER | bRegIdx);
+ DM9000Write(DM9000_EPAR, bPhyAddr << 6 | bRegIdx);
DM9000Write(DM9000_EPDRL, hVal & 0xff);
DM9000Write(DM9000_EPDRH, (hVal >> 8) & 0xff);
@@ -202,43 +199,6 @@ static int DM9000RecvPacket(void)
}
-static int DM9000GetLinkStatus(void)
-{
- int i;
-
- for(i = 0; i < 30; i++)
- {
- if (DM9000PhyRead(MII_REG_BMS) & 0x20)
- goto L1;
-
- mdelay(100);
- }
-
- return -EIO;
-
-L1:
- switch (DM9000PhyRead(MII_REG_STAT) >> 12)
- {
- case 1:
- return ETHER_SPEED_10M_HD;
-
- case 2:
- return ETHER_SPEED_10M_FD;
-
- case 4:
- return ETHER_SPEED_100M_HD;
-
- case 8:
- return ETHER_SPEED_100M_FD;
-
- default:
- break;
- }
-
- return ETHER_SPEED_UNKNOW;
-}
-
-
static int DM9000Isr(void *pDev)
{
BYTE bStat;
@@ -268,9 +228,9 @@ static int __INIT__ DM9000Init(void)
BYTE bRev;
BYTE bStat;
struct NetDevice *pNetDev;
+ struct PhyDevice *pPhyDev;
const char *pcChipName;
-
hVID = (DM9000Read(DM9000_VIDH) << 8) | DM9000Read(DM9000_VIDL);
hPID = (DM9000Read(DM9000_PIDH) << 8) | DM9000Read(DM9000_PIDL);
@@ -299,9 +259,25 @@ static int __INIT__ DM9000Init(void)
DM9000Reset();
+ pPhyDev = GkPhyDevNew();
+ if (!pPhyDev)
+ {
+ return -EIO;
+ }
+
+ pPhyDev->PhyRead = DM9000PhyRead;
+ pPhyDev->PhyWrite = DM9000PhyWrite;
+
+ if (GkPhyDevRegister(pPhyDev) < 0)
+ {
+ return -EIO;
+ }
+
+ GkPhyResetPhy();
+
printf("Detecting ethernet speed ... ");
- iSpeed = DM9000GetLinkStatus();
+ iSpeed = GkPhyGetLinkStatus();
if (iSpeed < 0)
{
--
1.6.3.3
g-bios添加了MII CORE层后,修改了AT91SAM9263网卡驱动相关代码。
signed-off-by: voidjackjiang <voidjack@163.com>
--------------------------------------------------------------------------------------
From 25fd823fa78accd54cb06741955727f896fee39a Mon Sep 17 00:00:00 2001
From: Jack Jiang <voidjack.jiang@gmail.com>
Date: Tue, 17 Nov 2009 22:51:33 +0800
Subject: [PATCH 3/3] Add mii function for AT92SAM9263's EMAC
---
device/net/eth_at91.c | 90 +++++++++++++++++++++++++++----------------------
1 files changed, 50 insertions(+), 40 deletions(-)
diff --git a/device/net/eth_at91.c b/device/net/eth_at91.c
index c7388c0..3465191 100644
--- a/device/net/eth_at91.c
+++ b/device/net/eth_at91.c
@@ -1,5 +1,6 @@
#include <stdio.h>
#include <core/types.h>
+#include <core/errno.h>
#include <core/io.h>
#include <core/init.h>
#include <core/list.h>
@@ -142,13 +143,12 @@ static int EmacRecv(struct NetDevice * pNetDev)
return 0;
}
-static UINT16 EmacMdioRead(UINT32 nReg)
+static UINT16 EmacMdioRead(UINT8 bPhyAddr, UINT8 bPhyReg)
{
UINT32 dwNetCtrl;
UINT32 dwFrame;
-
- dwFrame = (1 << 30) | (2 << 28) | (0 << 23) | (nReg << 18) | (2 << 16);
+ dwFrame = (1 << 30) | (2 << 28) | (bPhyAddr << 23) | (bPhyReg << 18) | (2 << 16);
EmacWrite(EMAC_MAN, dwFrame);
while (!(EmacRead(EMAC_NSR) & EMAC_IDLE));
@@ -158,13 +158,11 @@ static UINT16 EmacMdioRead(UINT32 nReg)
return (UINT16)(dwFrame & 0xffff);
}
-static int EmacMdioWrite(UINT32 nReg, UINT16 hVal)
+static void EmacMdioWrite(UINT16 hVal, UINT8 bPhyAddr, UINT8 bPhyReg)
{
- EmacWrite(EMAC_MAN, (1 << 30) | (1 << 28) | (0 << 23) | (nReg << 18) | (2 << 16) | hVal);
+ EmacWrite(EMAC_MAN, (1 << 30) | (1 << 28) | (bPhyAddr << 23) | (bPhyReg << 18) | (2 << 16) | hVal);
while (!(EmacRead(EMAC_NSR) & EMAC_IDLE));
-
- return 0;
}
static int __INIT__ EmacInitRingBuff(struct At91Emac *pEmac)
@@ -205,7 +203,7 @@ static int __INIT__ EmacInitRingBuff(struct At91Emac *pEmac)
EmacWrite(EMAC_TBQP, (UINT32)pEmac->pTxQueue);
DPRINT("RX buff = 0x%08x, TX buff = 0x%08x\n",
- pEmac->pRxQueue, pEmac->pTxQueue);
+ pEmac->pRxQueue, pEmac->pTxQueue);
return 0;
}
@@ -236,26 +234,6 @@ static void __INIT__ EmacInit(struct At91Emac *pEmac)
EmacWrite(EMAC_USRIO, 0x3);
}
-static void __INIT__ EmacPhyReset(void)
-{
- UINT16 hVal;
- int nTimeOut = 100;
-
- EmacMdioWrite(MII_REG_BMC, MII_PHY_RESET);
-
- while (nTimeOut > 0)
- {
- hVal = EmacMdioRead(MII_REG_BMC);
- if (!(hVal & MII_PHY_RESET))
- return;
-
- udelay(10);
- nTimeOut--;
- }
-
- printf("PHY reset failed!\n");
-}
-
static int EmacSetMacAddr(struct NetDevice *pNetDev, const BYTE vbMacAddr[])
{
EmacWrite(EMAC_SA1B, *(UINT32 *)pNetDev->vbMacAddr);
@@ -268,9 +246,9 @@ static int __INIT__ EmacProbe(void)
{
UINT16 hSpeed, hMode;
struct NetDevice *pNetDev;
+ struct PhyDevice *pPhyDev;
struct At91Emac *pEmac;
-
pNetDev = GkNetDevNew(sizeof(*pEmac));
pEmac = pNetDev->pChip;
@@ -278,23 +256,55 @@ static int __INIT__ EmacProbe(void)
EmacInit(pEmac);
- EmacPhyReset();
+ pPhyDev = GkPhyDevNew();
+ if (!pPhyDev)
+ {
+ return -EIO;
+ }
- while (1) // fixme
+ pPhyDev->PhyRead = EmacMdioRead;
+ pPhyDev->PhyWrite = EmacMdioWrite;
+
+ if (GkPhyDevRegister(pPhyDev) < 0)
{
- hMode = EmacMdioRead(MII_REG_BMS);
- if (hMode & 0x24)
- break;
+ return -EIO;
}
- if(hMode & 0x20)
- printf("Auto negotiation ok!\n");
- if(hMode & 0x4)
- printf("Link ok!\n");
+ GkPhyResetPhy();
- hSpeed = EmacMdioRead(MII_REG_STAT);
+ printf("Detecting ethernet speed ... ");
- printf("hSpeed = 0x%04x\n", hSpeed);
+ hSpeed = GkPhyGetLinkStatus();
+
+ if (hSpeed < 0)
+ {
+ printf("NOT linked, please check the cable!\n");
+ }
+ else
+ {
+ switch(hSpeed)
+ {
+ case ETHER_SPEED_10M_HD:
+ printf("10M Half Duplex activated!\n");
+ break;
+
+ case ETHER_SPEED_10M_FD:
+ printf("10M Full Duplex activated!\n");
+ break;
+
+ case ETHER_SPEED_100M_HD:
+ printf("100M Half Duplex activated!\n");
+ break;
+
+ case ETHER_SPEED_100M_FD:
+ printf("100M Full Duplex activated!\n");
+ break;
+
+ default:
+ printf("Unknown speed (%d)!\n", hSpeed);
+ break;
+ }
+ }
pNetDev->SendPacket = EmacSendPacket;
pNetDev->SetMacAddr = EmacSetMacAddr;
--
1.6.3.3