Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OS
U-Boot.Mirror
提交
65d4a75f
U
U-Boot.Mirror
项目概览
OS
/
U-Boot.Mirror
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
U
U-Boot.Mirror
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
65d4a75f
编写于
10月 14, 2008
作者:
W
Wolfgang Denk
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'master' of
git://git.denx.de/u-boot-net
上级
0e8a7b2f
30f57471
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
1939 addition
and
723 deletion
+1939
-723
drivers/net/Makefile
drivers/net/Makefile
+3
-4
drivers/net/ax88180.c
drivers/net/ax88180.c
+727
-0
drivers/net/ax88180.h
drivers/net/ax88180.h
+412
-0
drivers/net/ax88796.c
drivers/net/ax88796.c
+1
-1
drivers/net/ne2000.c
drivers/net/ne2000.c
+7
-712
drivers/net/ne2000_base.c
drivers/net/ne2000_base.c
+757
-0
drivers/net/ne2000_base.h
drivers/net/ne2000_base.h
+30
-6
drivers/net/tsec.c
drivers/net/tsec.c
+2
-0
未找到文件。
drivers/net/Makefile
浏览文件 @
65d4a75f
...
...
@@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk
LIB
:=
$(obj)
libnet.a
COBJS-$(CONFIG_DRIVER_3C589)
+=
3c589.o
COBJS-$(CONFIG_DRIVER_AX88180)
+=
ax88180.o
COBJS-$(CONFIG_BCM570x)
+=
bcm570x.o bcm570x_autoneg.o 5701rls.o
COBJS-$(CONFIG_BFIN_MAC)
+=
bfin_mac.o
COBJS-$(CONFIG_DRIVER_CS8900)
+=
cs8900.o
...
...
@@ -44,10 +45,8 @@ COBJS-$(CONFIG_MCFFEC) += mcffec.o
COBJS-$(CONFIG_MPC5xxx_FEC)
+=
mpc5xxx_fec.o
COBJS-$(CONFIG_MPC512x_FEC)
+=
mpc512x_fec.o
COBJS-$(CONFIG_NATSEMI)
+=
natsemi.o
ifeq
($(CONFIG_DRIVER_NE2000),y)
COBJS-y
+=
ne2000.o
COBJS-$(CONFIG_DRIVER_AX88796L)
+=
ax88796.o
endif
COBJS-$(CONFIG_DRIVER_NE2000)
+=
ne2000.o ne2000_base.o
COBJS-$(CONFIG_DRIVER_AX88796L)
+=
ax88796.o ne2000_base.o
COBJS-$(CONFIG_DRIVER_NETARMETH)
+=
netarm_eth.o
COBJS-$(CONFIG_NETCONSOLE)
+=
netconsole.o
COBJS-$(CONFIG_DRIVER_NS7520_ETHERNET)
+=
ns7520_eth.o
...
...
drivers/net/ax88180.c
0 → 100644
浏览文件 @
65d4a75f
/*
* ax88180: ASIX AX88180 Non-PCI Gigabit Ethernet u-boot driver
*
* This program is free software; you can distribute it and/or modify
* it under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
* This program is distributed in the hope it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
* USA.
*/
/*
* ========================================================================
* ASIX AX88180 Non-PCI 16/32-bit Gigabit Ethernet Linux Driver
*
* The AX88180 Ethernet controller is a high performance and highly
* integrated local CPU bus Ethernet controller with embedded 40K bytes
* SRAM and supports both 16-bit and 32-bit SRAM-Like interfaces for any
* embedded systems.
* The AX88180 is a single chip 10/100/1000Mbps Gigabit Ethernet
* controller that supports both MII and RGMII interfaces and is
* compliant to IEEE 802.3, IEEE 802.3u and IEEE 802.3z standards.
*
* Please visit ASIX's web site (http://www.asix.com.tw) for more
* details.
*
* Module Name : ax88180.c
* Date : 2008-07-07
* History
* 09/06/2006 : New release for AX88180 US2 chip.
* 07/07/2008 : Fix up the coding style and using inline functions
* instead of macros
* ========================================================================
*/
#include <common.h>
#include <command.h>
#include <net.h>
#include <malloc.h>
#include "ax88180.h"
/*
* ===========================================================================
* Local SubProgram Declaration
* ===========================================================================
*/
static
void
ax88180_rx_handler
(
struct
eth_device
*
dev
);
static
int
ax88180_phy_initial
(
struct
eth_device
*
dev
);
static
void
ax88180_meidia_config
(
struct
eth_device
*
dev
);
static
unsigned
long
get_CicadaPHY_meida_mode
(
struct
eth_device
*
dev
);
static
unsigned
long
get_MarvellPHY_meida_mode
(
struct
eth_device
*
dev
);
static
unsigned
short
ax88180_mdio_read
(
struct
eth_device
*
dev
,
unsigned
long
regaddr
);
static
void
ax88180_mdio_write
(
struct
eth_device
*
dev
,
unsigned
long
regaddr
,
unsigned
short
regdata
);
/*
* ===========================================================================
* Local SubProgram Bodies
* ===========================================================================
*/
static
int
ax88180_mdio_check_complete
(
struct
eth_device
*
dev
)
{
int
us_cnt
=
10000
;
unsigned
short
tmpval
;
/* MDIO read/write should not take more than 10 ms */
while
(
--
us_cnt
)
{
tmpval
=
INW
(
dev
,
MDIOCTRL
);
if
(((
tmpval
&
READ_PHY
)
==
0
)
&&
((
tmpval
&
WRITE_PHY
)
==
0
))
break
;
}
return
us_cnt
;
}
static
unsigned
short
ax88180_mdio_read
(
struct
eth_device
*
dev
,
unsigned
long
regaddr
)
{
struct
ax88180_private
*
priv
=
(
struct
ax88180_private
*
)
dev
->
priv
;
unsigned
long
tmpval
=
0
;
OUTW
(
dev
,
(
READ_PHY
|
(
regaddr
<<
8
)
|
priv
->
PhyAddr
),
MDIOCTRL
);
if
(
ax88180_mdio_check_complete
(
dev
))
tmpval
=
INW
(
dev
,
MDIODP
);
else
printf
(
"Failed to read PHY register!
\n
"
);
return
(
unsigned
short
)(
tmpval
&
0xFFFF
);
}
static
void
ax88180_mdio_write
(
struct
eth_device
*
dev
,
unsigned
long
regaddr
,
unsigned
short
regdata
)
{
struct
ax88180_private
*
priv
=
(
struct
ax88180_private
*
)
dev
->
priv
;
OUTW
(
dev
,
regdata
,
MDIODP
);
OUTW
(
dev
,
(
WRITE_PHY
|
(
regaddr
<<
8
)
|
priv
->
PhyAddr
),
MDIOCTRL
);
if
(
!
ax88180_mdio_check_complete
(
dev
))
printf
(
"Failed to write PHY register!
\n
"
);
}
static
int
ax88180_phy_reset
(
struct
eth_device
*
dev
)
{
unsigned
short
delay_cnt
=
500
;
ax88180_mdio_write
(
dev
,
BMCR
,
(
PHY_RESET
|
AUTONEG_EN
));
/* Wait for the reset to complete, or time out (500 ms) */
while
(
ax88180_mdio_read
(
dev
,
BMCR
)
&
PHY_RESET
)
{
udelay
(
1000
);
if
(
--
delay_cnt
==
0
)
{
printf
(
"Failed to reset PHY!
\n
"
);
return
-
1
;
}
}
return
0
;
}
static
void
ax88180_mac_reset
(
struct
eth_device
*
dev
)
{
unsigned
long
tmpval
;
unsigned
char
i
;
struct
{
unsigned
short
offset
,
value
;
}
program_seq
[]
=
{
{
MISC
,
MISC_NORMAL
},
{
RXINDICATOR
,
DEFAULT_RXINDICATOR
},
{
TXCMD
,
DEFAULT_TXCMD
},
{
TXBS
,
DEFAULT_TXBS
},
{
TXDES0
,
DEFAULT_TXDES0
},
{
TXDES1
,
DEFAULT_TXDES1
},
{
TXDES2
,
DEFAULT_TXDES2
},
{
TXDES3
,
DEFAULT_TXDES3
},
{
TXCFG
,
DEFAULT_TXCFG
},
{
MACCFG2
,
DEFAULT_MACCFG2
},
{
MACCFG3
,
DEFAULT_MACCFG3
},
{
TXLEN
,
DEFAULT_TXLEN
},
{
RXBTHD0
,
DEFAULT_RXBTHD0
},
{
RXBTHD1
,
DEFAULT_RXBTHD1
},
{
RXFULTHD
,
DEFAULT_RXFULTHD
},
{
DOGTHD0
,
DEFAULT_DOGTHD0
},
{
DOGTHD1
,
DEFAULT_DOGTHD1
},};
OUTW
(
dev
,
MISC_RESET_MAC
,
MISC
);
tmpval
=
INW
(
dev
,
MISC
);
for
(
i
=
0
;
i
<
(
sizeof
(
program_seq
)
/
sizeof
(
program_seq
[
0
]));
i
++
)
OUTW
(
dev
,
program_seq
[
i
].
value
,
program_seq
[
i
].
offset
);
}
static
int
ax88180_poll_tx_complete
(
struct
eth_device
*
dev
)
{
struct
ax88180_private
*
priv
=
(
struct
ax88180_private
*
)
dev
->
priv
;
unsigned
long
tmpval
,
txbs_txdp
;
int
TimeOutCnt
=
10000
;
txbs_txdp
=
1
<<
priv
->
NextTxDesc
;
while
(
TimeOutCnt
--
)
{
tmpval
=
INW
(
dev
,
TXBS
);
if
((
tmpval
&
txbs_txdp
)
==
0
)
break
;
udelay
(
100
);
}
if
(
TimeOutCnt
)
return
0
;
else
return
-
TimeOutCnt
;
}
static
void
ax88180_rx_handler
(
struct
eth_device
*
dev
)
{
struct
ax88180_private
*
priv
=
(
struct
ax88180_private
*
)
dev
->
priv
;
unsigned
long
data_size
;
unsigned
short
rxcurt_ptr
,
rxbound_ptr
,
next_ptr
;
int
i
;
#if defined (CONFIG_DRIVER_AX88180_16BIT)
unsigned
short
*
rxdata
=
(
unsigned
short
*
)
NetRxPackets
[
0
];
#else
unsigned
long
*
rxdata
=
(
unsigned
long
*
)
NetRxPackets
[
0
];
#endif
unsigned
short
count
;
rxcurt_ptr
=
INW
(
dev
,
RXCURT
);
rxbound_ptr
=
INW
(
dev
,
RXBOUND
);
next_ptr
=
(
rxbound_ptr
+
1
)
&
RX_PAGE_NUM_MASK
;
debug
(
"ax88180: RX original RXBOUND=0x%04x,"
" RXCURT=0x%04x
\n
"
,
rxbound_ptr
,
rxcurt_ptr
);
while
(
next_ptr
!=
rxcurt_ptr
)
{
OUTW
(
dev
,
RX_START_READ
,
RXINDICATOR
);
data_size
=
READ_RXBUF
(
dev
)
&
0xFFFF
;
if
((
data_size
==
0
)
||
(
data_size
>
MAX_RX_SIZE
))
{
OUTW
(
dev
,
RX_STOP_READ
,
RXINDICATOR
);
ax88180_mac_reset
(
dev
);
printf
(
"ax88180: Invalid Rx packet length!"
" (len=0x%04lx)
\n
"
,
data_size
);
debug
(
"ax88180: RX RXBOUND=0x%04x,"
"RXCURT=0x%04x
\n
"
,
rxbound_ptr
,
rxcurt_ptr
);
return
;
}
rxbound_ptr
+=
(((
data_size
+
0xF
)
&
0xFFF0
)
>>
4
)
+
1
;
rxbound_ptr
&=
RX_PAGE_NUM_MASK
;
/* Comput access times */
count
=
(
data_size
+
priv
->
PadSize
)
>>
priv
->
BusWidth
;
for
(
i
=
0
;
i
<
count
;
i
++
)
{
*
(
rxdata
+
i
)
=
READ_RXBUF
(
dev
);
}
OUTW
(
dev
,
RX_STOP_READ
,
RXINDICATOR
);
/* Pass the packet up to the protocol layers. */
NetReceive
(
NetRxPackets
[
0
],
data_size
);
OUTW
(
dev
,
rxbound_ptr
,
RXBOUND
);
rxcurt_ptr
=
INW
(
dev
,
RXCURT
);
rxbound_ptr
=
INW
(
dev
,
RXBOUND
);
next_ptr
=
(
rxbound_ptr
+
1
)
&
RX_PAGE_NUM_MASK
;
debug
(
"ax88180: RX updated RXBOUND=0x%04x,"
"RXCURT=0x%04x
\n
"
,
rxbound_ptr
,
rxcurt_ptr
);
}
return
;
}
static
int
ax88180_phy_initial
(
struct
eth_device
*
dev
)
{
struct
ax88180_private
*
priv
=
(
struct
ax88180_private
*
)
dev
->
priv
;
unsigned
long
tmp_regval
;
/* Check avaliable PHY chipset */
priv
->
PhyAddr
=
MARVELL_88E1111_PHYADDR
;
priv
->
PhyID0
=
ax88180_mdio_read
(
dev
,
PHYIDR0
);
if
(
priv
->
PhyID0
==
MARVELL_88E1111_PHYIDR0
)
{
debug
(
"ax88180: Found Marvell 88E1111 PHY."
" (PHY Addr=0x%x)
\n
"
,
priv
->
PhyAddr
);
tmp_regval
=
ax88180_mdio_read
(
dev
,
M88_EXT_SSR
);
if
((
tmp_regval
&
HWCFG_MODE_MASK
)
==
RGMII_COPPER_MODE
)
{
ax88180_mdio_write
(
dev
,
M88_EXT_SCR
,
DEFAULT_EXT_SCR
);
if
(
ax88180_phy_reset
(
dev
)
<
0
)
return
0
;
ax88180_mdio_write
(
dev
,
M88_IER
,
LINK_CHANGE_INT
);
}
}
else
{
priv
->
PhyAddr
=
CICADA_CIS8201_PHYADDR
;
priv
->
PhyID0
=
ax88180_mdio_read
(
dev
,
PHYIDR0
);
if
(
priv
->
PhyID0
==
CICADA_CIS8201_PHYIDR0
)
{
debug
(
"ax88180: Found CICADA CIS8201 PHY"
" chipset. (PHY Addr=0x%x)
\n
"
,
priv
->
PhyAddr
);
ax88180_mdio_write
(
dev
,
CIS_IMR
,
(
CIS_INT_ENABLE
|
LINK_CHANGE_INT
));
/* Set CIS_SMI_PRIORITY bit before force the media mode */
tmp_regval
=
ax88180_mdio_read
(
dev
,
CIS_AUX_CTRL_STATUS
);
tmp_regval
&=
~
CIS_SMI_PRIORITY
;
ax88180_mdio_write
(
dev
,
CIS_AUX_CTRL_STATUS
,
tmp_regval
);
}
else
{
printf
(
"ax88180: Unknown PHY chipset!!
\n
"
);
return
0
;
}
}
return
1
;
}
static
void
ax88180_meidia_config
(
struct
eth_device
*
dev
)
{
struct
ax88180_private
*
priv
=
(
struct
ax88180_private
*
)
dev
->
priv
;
unsigned
long
bmcr_val
,
bmsr_val
;
unsigned
long
rxcfg_val
,
maccfg0_val
,
maccfg1_val
;
unsigned
long
RealMediaMode
;
int
i
;
/* Waiting 2 seconds for PHY link stable */
for
(
i
=
0
;
i
<
20000
;
i
++
)
{
bmsr_val
=
ax88180_mdio_read
(
dev
,
BMSR
);
if
(
bmsr_val
&
LINKOK
)
{
break
;
}
udelay
(
100
);
}
bmsr_val
=
ax88180_mdio_read
(
dev
,
BMSR
);
debug
(
"ax88180: BMSR=0x%04x
\n
"
,
(
unsigned
int
)
bmsr_val
);
if
(
bmsr_val
&
LINKOK
)
{
bmcr_val
=
ax88180_mdio_read
(
dev
,
BMCR
);
if
(
bmcr_val
&
AUTONEG_EN
)
{
/*
* Waiting for Auto-negotiation completion, this may
* take up to 5 seconds.
*/
debug
(
"ax88180: Auto-negotiation is "
"enabled. Waiting for NWay completion..
\n
"
);
for
(
i
=
0
;
i
<
50000
;
i
++
)
{
bmsr_val
=
ax88180_mdio_read
(
dev
,
BMSR
);
if
(
bmsr_val
&
AUTONEG_COMPLETE
)
{
break
;
}
udelay
(
100
);
}
}
else
debug
(
"ax88180: Auto-negotiation is disabled.
\n
"
);
debug
(
"ax88180: BMCR=0x%04x, BMSR=0x%04x
\n
"
,
(
unsigned
int
)
bmcr_val
,
(
unsigned
int
)
bmsr_val
);
/* Get real media mode here */
if
(
priv
->
PhyID0
==
MARVELL_88E1111_PHYIDR0
)
{
RealMediaMode
=
get_MarvellPHY_meida_mode
(
dev
);
}
else
if
(
priv
->
PhyID0
==
CICADA_CIS8201_PHYIDR0
)
{
RealMediaMode
=
get_CicadaPHY_meida_mode
(
dev
);
}
else
{
RealMediaMode
=
MEDIA_1000FULL
;
}
priv
->
LinkState
=
INS_LINK_UP
;
switch
(
RealMediaMode
)
{
case
MEDIA_1000FULL
:
debug
(
"ax88180: 1000Mbps Full-duplex mode.
\n
"
);
rxcfg_val
=
RXFLOW_ENABLE
|
DEFAULT_RXCFG
;
maccfg0_val
=
TXFLOW_ENABLE
|
DEFAULT_MACCFG0
;
maccfg1_val
=
GIGA_MODE_EN
|
RXFLOW_EN
|
FULLDUPLEX
|
DEFAULT_MACCFG1
;
break
;
case
MEDIA_1000HALF
:
debug
(
"ax88180: 1000Mbps Half-duplex mode.
\n
"
);
rxcfg_val
=
DEFAULT_RXCFG
;
maccfg0_val
=
DEFAULT_MACCFG0
;
maccfg1_val
=
GIGA_MODE_EN
|
DEFAULT_MACCFG1
;
break
;
case
MEDIA_100FULL
:
debug
(
"ax88180: 100Mbps Full-duplex mode.
\n
"
);
rxcfg_val
=
RXFLOW_ENABLE
|
DEFAULT_RXCFG
;
maccfg0_val
=
SPEED100
|
TXFLOW_ENABLE
|
DEFAULT_MACCFG0
;
maccfg1_val
=
RXFLOW_EN
|
FULLDUPLEX
|
DEFAULT_MACCFG1
;
break
;
case
MEDIA_100HALF
:
debug
(
"ax88180: 100Mbps Half-duplex mode.
\n
"
);
rxcfg_val
=
DEFAULT_RXCFG
;
maccfg0_val
=
SPEED100
|
DEFAULT_MACCFG0
;
maccfg1_val
=
DEFAULT_MACCFG1
;
break
;
case
MEDIA_10FULL
:
debug
(
"ax88180: 10Mbps Full-duplex mode.
\n
"
);
rxcfg_val
=
RXFLOW_ENABLE
|
DEFAULT_RXCFG
;
maccfg0_val
=
TXFLOW_ENABLE
|
DEFAULT_MACCFG0
;
maccfg1_val
=
RXFLOW_EN
|
FULLDUPLEX
|
DEFAULT_MACCFG1
;
break
;
case
MEDIA_10HALF
:
debug
(
"ax88180: 10Mbps Half-duplex mode.
\n
"
);
rxcfg_val
=
DEFAULT_RXCFG
;
maccfg0_val
=
DEFAULT_MACCFG0
;
maccfg1_val
=
DEFAULT_MACCFG1
;
break
;
default:
debug
(
"ax88180: Unknow media mode.
\n
"
);
rxcfg_val
=
DEFAULT_RXCFG
;
maccfg0_val
=
DEFAULT_MACCFG0
;
maccfg1_val
=
DEFAULT_MACCFG1
;
priv
->
LinkState
=
INS_LINK_DOWN
;
break
;
}
}
else
{
rxcfg_val
=
DEFAULT_RXCFG
;
maccfg0_val
=
DEFAULT_MACCFG0
;
maccfg1_val
=
DEFAULT_MACCFG1
;
priv
->
LinkState
=
INS_LINK_DOWN
;
}
OUTW
(
dev
,
rxcfg_val
,
RXCFG
);
OUTW
(
dev
,
maccfg0_val
,
MACCFG0
);
OUTW
(
dev
,
maccfg1_val
,
MACCFG1
);
return
;
}
static
unsigned
long
get_MarvellPHY_meida_mode
(
struct
eth_device
*
dev
)
{
unsigned
long
m88_ssr
;
unsigned
long
MediaMode
;
m88_ssr
=
ax88180_mdio_read
(
dev
,
M88_SSR
);
switch
(
m88_ssr
&
SSR_MEDIA_MASK
)
{
case
SSR_1000FULL
:
MediaMode
=
MEDIA_1000FULL
;
break
;
case
SSR_1000HALF
:
MediaMode
=
MEDIA_1000HALF
;
break
;
case
SSR_100FULL
:
MediaMode
=
MEDIA_100FULL
;
break
;
case
SSR_100HALF
:
MediaMode
=
MEDIA_100HALF
;
break
;
case
SSR_10FULL
:
MediaMode
=
MEDIA_10FULL
;
break
;
case
SSR_10HALF
:
MediaMode
=
MEDIA_10HALF
;
break
;
default:
MediaMode
=
MEDIA_UNKNOWN
;
break
;
}
return
MediaMode
;
}
static
unsigned
long
get_CicadaPHY_meida_mode
(
struct
eth_device
*
dev
)
{
unsigned
long
tmp_regval
;
unsigned
long
MediaMode
;
tmp_regval
=
ax88180_mdio_read
(
dev
,
CIS_AUX_CTRL_STATUS
);
switch
(
tmp_regval
&
CIS_MEDIA_MASK
)
{
case
CIS_1000FULL
:
MediaMode
=
MEDIA_1000FULL
;
break
;
case
CIS_1000HALF
:
MediaMode
=
MEDIA_1000HALF
;
break
;
case
CIS_100FULL
:
MediaMode
=
MEDIA_100FULL
;
break
;
case
CIS_100HALF
:
MediaMode
=
MEDIA_100HALF
;
break
;
case
CIS_10FULL
:
MediaMode
=
MEDIA_10FULL
;
break
;
case
CIS_10HALF
:
MediaMode
=
MEDIA_10HALF
;
break
;
default:
MediaMode
=
MEDIA_UNKNOWN
;
break
;
}
return
MediaMode
;
}
static
void
ax88180_halt
(
struct
eth_device
*
dev
)
{
/* Disable AX88180 TX/RX functions */
OUTW
(
dev
,
WAKEMOD
,
CMD
);
}
static
int
ax88180_init
(
struct
eth_device
*
dev
,
bd_t
*
bd
)
{
struct
ax88180_private
*
priv
=
(
struct
ax88180_private
*
)
dev
->
priv
;
unsigned
short
tmp_regval
;
ax88180_mac_reset
(
dev
);
/* Disable interrupt */
OUTW
(
dev
,
CLEAR_IMR
,
IMR
);
/* Disable AX88180 TX/RX functions */
OUTW
(
dev
,
WAKEMOD
,
CMD
);
/* Fill the MAC address */
tmp_regval
=
dev
->
enetaddr
[
0
]
|
(((
unsigned
short
)
dev
->
enetaddr
[
1
])
<<
8
);
OUTW
(
dev
,
tmp_regval
,
MACID0
);
tmp_regval
=
dev
->
enetaddr
[
2
]
|
(((
unsigned
short
)
dev
->
enetaddr
[
3
])
<<
8
);
OUTW
(
dev
,
tmp_regval
,
MACID1
);
tmp_regval
=
dev
->
enetaddr
[
4
]
|
(((
unsigned
short
)
dev
->
enetaddr
[
5
])
<<
8
);
OUTW
(
dev
,
tmp_regval
,
MACID2
);
ax88180_meidia_config
(
dev
);
OUTW
(
dev
,
DEFAULT_RXFILTER
,
RXFILTER
);
/* Initial variables here */
priv
->
FirstTxDesc
=
TXDP0
;
priv
->
NextTxDesc
=
TXDP0
;
/* Check if there is any invalid interrupt status and clear it. */
OUTW
(
dev
,
INW
(
dev
,
ISR
),
ISR
);
/* Start AX88180 TX/RX functions */
OUTW
(
dev
,
(
RXEN
|
TXEN
|
WAKEMOD
),
CMD
);
return
0
;
}
/* Get a data block via Ethernet */
static
int
ax88180_recv
(
struct
eth_device
*
dev
)
{
unsigned
short
ISR_Status
;
unsigned
short
tmp_regval
;
/* Read and check interrupt status here. */
ISR_Status
=
INW
(
dev
,
ISR
);
while
(
ISR_Status
)
{
/* Clear the interrupt status */
OUTW
(
dev
,
ISR_Status
,
ISR
);
debug
(
"
\n
ax88180: The interrupt status = 0x%04x
\n
"
,
ISR_Status
);
if
(
ISR_Status
&
ISR_PHY
)
{
/* Read ISR register once to clear PHY interrupt bit */
tmp_regval
=
ax88180_mdio_read
(
dev
,
M88_ISR
);
ax88180_meidia_config
(
dev
);
}
if
((
ISR_Status
&
ISR_RX
)
||
(
ISR_Status
&
ISR_RXBUFFOVR
))
{
ax88180_rx_handler
(
dev
);
}
/* Read and check interrupt status again */
ISR_Status
=
INW
(
dev
,
ISR
);
}
return
0
;
}
/* Send a data block via Ethernet. */
static
int
ax88180_send
(
struct
eth_device
*
dev
,
volatile
void
*
packet
,
int
length
)
{
struct
ax88180_private
*
priv
=
(
struct
ax88180_private
*
)
dev
->
priv
;
unsigned
short
TXDES_addr
;
unsigned
short
txcmd_txdp
,
txbs_txdp
;
unsigned
short
tmp_data
;
int
i
;
#if defined (CONFIG_DRIVER_AX88180_16BIT)
volatile
unsigned
short
*
txdata
=
(
volatile
unsigned
short
*
)
packet
;
#else
volatile
unsigned
long
*
txdata
=
(
volatile
unsigned
long
*
)
packet
;
#endif
unsigned
short
count
;
if
(
priv
->
LinkState
!=
INS_LINK_UP
)
{
return
0
;
}
priv
->
FirstTxDesc
=
priv
->
NextTxDesc
;
txbs_txdp
=
1
<<
priv
->
FirstTxDesc
;
debug
(
"ax88180: TXDP%d is available
\n
"
,
priv
->
FirstTxDesc
);
txcmd_txdp
=
priv
->
FirstTxDesc
<<
13
;
TXDES_addr
=
TXDES0
+
(
priv
->
FirstTxDesc
<<
2
);
OUTW
(
dev
,
(
txcmd_txdp
|
length
|
TX_START_WRITE
),
TXCMD
);
/* Comput access times */
count
=
(
length
+
priv
->
PadSize
)
>>
priv
->
BusWidth
;
for
(
i
=
0
;
i
<
count
;
i
++
)
{
WRITE_TXBUF
(
dev
,
*
(
txdata
+
i
));
}
OUTW
(
dev
,
txcmd_txdp
|
length
,
TXCMD
);
OUTW
(
dev
,
txbs_txdp
,
TXBS
);
OUTW
(
dev
,
(
TXDPx_ENABLE
|
length
),
TXDES_addr
);
priv
->
NextTxDesc
=
(
priv
->
NextTxDesc
+
1
)
&
TXDP_MASK
;
/*
* Check the available transmit descriptor, if we had exhausted all
* transmit descriptor ,then we have to wait for at least one free
* descriptor
*/
txbs_txdp
=
1
<<
priv
->
NextTxDesc
;
tmp_data
=
INW
(
dev
,
TXBS
);
if
(
tmp_data
&
txbs_txdp
)
{
if
(
ax88180_poll_tx_complete
(
dev
)
<
0
)
{
ax88180_mac_reset
(
dev
);
priv
->
FirstTxDesc
=
TXDP0
;
priv
->
NextTxDesc
=
TXDP0
;
printf
(
"ax88180: Transmit time out occurred!
\n
"
);
}
}
return
0
;
}
static
void
ax88180_read_mac_addr
(
struct
eth_device
*
dev
)
{
unsigned
short
macid0_val
,
macid1_val
,
macid2_val
;
unsigned
short
tmp_regval
;
unsigned
short
i
;
/* Reload MAC address from EEPROM */
OUTW
(
dev
,
RELOAD_EEPROM
,
PROMCTRL
);
/* Waiting for reload eeprom completion */
for
(
i
=
0
;
i
<
500
;
i
++
)
{
tmp_regval
=
INW
(
dev
,
PROMCTRL
);
if
((
tmp_regval
&
RELOAD_EEPROM
)
==
0
)
break
;
udelay
(
1000
);
}
/* Get MAC addresses */
macid0_val
=
INW
(
dev
,
MACID0
);
macid1_val
=
INW
(
dev
,
MACID1
);
macid2_val
=
INW
(
dev
,
MACID2
);
if
(((
macid0_val
|
macid1_val
|
macid2_val
)
!=
0
)
&&
((
macid0_val
&
0x01
)
==
0
))
{
dev
->
enetaddr
[
0
]
=
(
unsigned
char
)
macid0_val
;
dev
->
enetaddr
[
1
]
=
(
unsigned
char
)(
macid0_val
>>
8
);
dev
->
enetaddr
[
2
]
=
(
unsigned
char
)
macid1_val
;
dev
->
enetaddr
[
3
]
=
(
unsigned
char
)(
macid1_val
>>
8
);
dev
->
enetaddr
[
4
]
=
(
unsigned
char
)
macid2_val
;
dev
->
enetaddr
[
5
]
=
(
unsigned
char
)(
macid2_val
>>
8
);
}
}
/*
===========================================================================
<<<<<< Exported SubProgram Bodies >>>>>>
===========================================================================
*/
int
ax88180_initialize
(
bd_t
*
bis
)
{
struct
eth_device
*
dev
;
struct
ax88180_private
*
priv
;
dev
=
(
struct
eth_device
*
)
malloc
(
sizeof
*
dev
);
if
(
NULL
==
dev
)
return
0
;
memset
(
dev
,
0
,
sizeof
*
dev
);
priv
=
(
struct
ax88180_private
*
)
malloc
(
sizeof
(
*
priv
));
if
(
NULL
==
priv
)
return
0
;
memset
(
priv
,
0
,
sizeof
*
priv
);
sprintf
(
dev
->
name
,
"ax88180"
);
dev
->
iobase
=
AX88180_BASE
;
dev
->
priv
=
priv
;
dev
->
init
=
ax88180_init
;
dev
->
halt
=
ax88180_halt
;
dev
->
send
=
ax88180_send
;
dev
->
recv
=
ax88180_recv
;
priv
->
BusWidth
=
BUS_WIDTH_32
;
priv
->
PadSize
=
3
;
#if defined (CONFIG_DRIVER_AX88180_16BIT)
OUTW
(
dev
,
(
START_BASE
>>
8
),
BASE
);
OUTW
(
dev
,
DECODE_EN
,
DECODE
);
priv
->
BusWidth
=
BUS_WIDTH_16
;
priv
->
PadSize
=
1
;
#endif
ax88180_mac_reset
(
dev
);
/* Disable interrupt */
OUTW
(
dev
,
CLEAR_IMR
,
IMR
);
/* Disable AX88180 TX/RX functions */
OUTW
(
dev
,
WAKEMOD
,
CMD
);
ax88180_read_mac_addr
(
dev
);
eth_register
(
dev
);
return
ax88180_phy_initial
(
dev
);
}
drivers/net/ax88180.h
0 → 100644
浏览文件 @
65d4a75f
/* ax88180.h: ASIX AX88180 Non-PCI Gigabit Ethernet u-boot driver */
/*
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*/
#ifndef _AX88180_H_
#define _AX88180_H_
#include <asm/types.h>
#include <config.h>
typedef
enum
_ax88180_link_state
{
INS_LINK_DOWN
,
INS_LINK_UP
,
INS_LINK_UNKNOWN
}
ax88180_link_state
;
struct
ax88180_private
{
unsigned
char
BusWidth
;
unsigned
char
PadSize
;
unsigned
short
PhyAddr
;
unsigned
short
PhyID0
;
unsigned
short
FirstTxDesc
;
unsigned
short
NextTxDesc
;
ax88180_link_state
LinkState
;
};
#define BUS_WIDTH_16 1
#define BUS_WIDTH_32 2
#define ENABLE_JUMBO 1
#define DISABLE_JUMBO 0
#define ENABLE_BURST 1
#define DISABLE_BURST 0
#define NORMAL_RX_MODE 0
#define RX_LOOPBACK_MODE 1
#define RX_INIFINIT_LOOP_MODE 2
#define TX_INIFINIT_LOOP_MODE 3
#define DEFAULT_ETH_MTU 1500
/* Jumbo packet size 4086 bytes included 4 bytes CRC*/
#define MAX_JUMBO_MTU 4072
/* Max Tx Jumbo size 4086 bytes included 4 bytes CRC */
#define MAX_TX_JUMBO_SIZE 4086
/* Max Rx Jumbo size is 15K Bytes */
#define MAX_RX_SIZE 0x3C00
#define MARVELL_88E1111_PHYADDR 0x18
#define MARVELL_88E1111_PHYIDR0 0x0141
#define CICADA_CIS8201_PHYADDR 0x01
#define CICADA_CIS8201_PHYIDR0 0x000F
#define MEDIA_AUTO 0
#define MEDIA_1000FULL 1
#define MEDIA_1000HALF 2
#define MEDIA_100FULL 3
#define MEDIA_100HALF 4
#define MEDIA_10FULL 5
#define MEDIA_10HALF 6
#define MEDIA_UNKNOWN 7
#define AUTO_MEDIA 0
#define FORCE_MEDIA 1
#define TXDP_MASK 3
#define TXDP0 0
#define TXDP1 1
#define TXDP2 2
#define TXDP3 3
#define CMD_MAP_SIZE 0x100
#if defined (CONFIG_DRIVER_AX88180_16BIT)
#define AX88180_MEMORY_SIZE 0x00004000
#define START_BASE 0x1000
#define RX_BUF_SIZE 0x1000
#define TX_BUF_SIZE 0x0F00
#define TX_BASE START_BASE
#define CMD_BASE (TX_BASE + TX_BUF_SIZE)
#define RX_BASE (CMD_BASE + CMD_MAP_SIZE)
#else
#define AX88180_MEMORY_SIZE 0x00010000
#define RX_BUF_SIZE 0x8000
#define TX_BUF_SIZE 0x7C00
#define RX_BASE 0x0000
#define TX_BASE (RX_BASE + RX_BUF_SIZE)
#define CMD_BASE (TX_BASE + TX_BUF_SIZE)
#endif
/* AX88180 Memory Mapping Definition */
#define RXBUFFER_START RX_BASE
#define RX_PACKET_LEN_OFFSET 0
#define RX_PAGE_NUM_MASK 0x7FF
/* RX pages 0~7FFh */
#define TXBUFFER_START TX_BASE
/* AX88180 MAC Register Definition */
#define DECODE (0)
#define DECODE_EN 0x00000001
#define BASE (6)
#define CMD (CMD_BASE + 0x0000)
#define WAKEMOD 0x00000001
#define TXEN 0x00000100
#define RXEN 0x00000200
#define DEFAULT_CMD WAKEMOD
#define IMR (CMD_BASE + 0x0004)
#define IMR_RXBUFFOVR 0x00000001
#define IMR_WATCHDOG 0x00000002
#define IMR_TX 0x00000008
#define IMR_RX 0x00000010
#define IMR_PHY 0x00000020
#define CLEAR_IMR 0x00000000
#define DEFAULT_IMR (IMR_PHY | IMR_RX | IMR_TX |\
IMR_RXBUFFOVR | IMR_WATCHDOG)
#define ISR (CMD_BASE + 0x0008)
#define ISR_RXBUFFOVR 0x00000001
#define ISR_WATCHDOG 0x00000002
#define ISR_TX 0x00000008
#define ISR_RX 0x00000010
#define ISR_PHY 0x00000020
#define TXCFG (CMD_BASE + 0x0010)
#define AUTOPAD_CRC 0x00000050
#define DEFAULT_TXCFG AUTOPAD_CRC
#define TXCMD (CMD_BASE + 0x0014)
#define TXCMD_TXDP_MASK 0x00006000
#define TXCMD_TXDP0 0x00000000
#define TXCMD_TXDP1 0x00002000
#define TXCMD_TXDP2 0x00004000
#define TXCMD_TXDP3 0x00006000
#define TX_START_WRITE 0x00008000
#define TX_STOP_WRITE 0x00000000
#define DEFAULT_TXCMD 0x00000000
#define TXBS (CMD_BASE + 0x0018)
#define TXDP0_USED 0x00000001
#define TXDP1_USED 0x00000002
#define TXDP2_USED 0x00000004
#define TXDP3_USED 0x00000008
#define DEFAULT_TXBS 0x00000000
#define TXDES0 (CMD_BASE + 0x0020)
#define TXDPx_ENABLE 0x00008000
#define TXDPx_LEN_MASK 0x00001FFF
#define DEFAULT_TXDES0 0x00000000
#define TXDES1 (CMD_BASE + 0x0024)
#define TXDPx_ENABLE 0x00008000
#define TXDPx_LEN_MASK 0x00001FFF
#define DEFAULT_TXDES1 0x00000000
#define TXDES2 (CMD_BASE + 0x0028)
#define TXDPx_ENABLE 0x00008000
#define TXDPx_LEN_MASK 0x00001FFF
#define DEFAULT_TXDES2 0x00000000
#define TXDES3 (CMD_BASE + 0x002C)
#define TXDPx_ENABLE 0x00008000
#define TXDPx_LEN_MASK 0x00001FFF
#define DEFAULT_TXDES3 0x00000000
#define RXCFG (CMD_BASE + 0x0030)
#define RXBUFF_PROTECT 0x00000001
#define RXTCPCRC_CHECK 0x00000010
#define RXFLOW_ENABLE 0x00000100
#define DEFAULT_RXCFG RXBUFF_PROTECT
#define RXCURT (CMD_BASE + 0x0034)
#define DEFAULT_RXCURT 0x00000000
#define RXBOUND (CMD_BASE + 0x0038)
#define DEFAULT_RXBOUND 0x7FF //RX pages 0~7FFh
#define MACCFG0 (CMD_BASE + 0x0040)
#define MACCFG0_BIT3_0 0x00000007
#define IPGT_VAL 0x00000150
#define TXFLOW_ENABLE 0x00001000
#define SPEED100 0x00008000
#define DEFAULT_MACCFG0 (IPGT_VAL | MACCFG0_BIT3_0)
#define MACCFG1 (CMD_BASE + 0x0044)
#define RGMII_EN 0x00000002
#define RXFLOW_EN 0x00000020
#define FULLDUPLEX 0x00000040
#define MAX_JUMBO_LEN 0x00000780
#define RXJUMBO_EN 0x00000800
#define GIGA_MODE_EN 0x00001000
#define RXCRC_CHECK 0x00002000
#define RXPAUSE_DA_CHECK 0x00004000
#define JUMBO_LEN_4K 0x00000200
#define JUMBO_LEN_15K 0x00000780
#define DEFAULT_MACCFG1 (RXCRC_CHECK | RXPAUSE_DA_CHECK | \
RGMII_EN)
#define CICADA_DEFAULT_MACCFG1 (RXCRC_CHECK | RXPAUSE_DA_CHECK)
#define MACCFG2 (CMD_BASE + 0x0048)
#define MACCFG2_BIT15_8 0x00000100
#define JAM_LIMIT_MASK 0x000000FC
#define DEFAULT_JAM_LIMIT 0x00000064
#define DEFAULT_MACCFG2 MACCFG2_BIT15_8
#define MACCFG3 (CMD_BASE + 0x004C)
#define IPGR2_VAL 0x0000000E
#define IPGR1_VAL 0x00000600
#define NOABORT 0x00008000
#define DEFAULT_MACCFG3 (IPGR1_VAL | IPGR2_VAL)
#define TXPAUT (CMD_BASE + 0x0054)
#define DEFAULT_TXPAUT 0x001FE000
#define RXBTHD0 (CMD_BASE + 0x0058)
#define DEFAULT_RXBTHD0 0x00000300
#define RXBTHD1 (CMD_BASE + 0x005C)
#define DEFAULT_RXBTHD1 0x00000600
#define RXFULTHD (CMD_BASE + 0x0060)
#define DEFAULT_RXFULTHD 0x00000100
#define MISC (CMD_BASE + 0x0068)
/* Normal operation mode */
#define MISC_NORMAL 0x00000003
/* Clear bit 0 to reset MAC */
#define MISC_RESET_MAC 0x00000002
/* Clear bit 1 to reset PHY */
#define MISC_RESET_PHY 0x00000001
/* Clear bit 0 and 1 to reset MAC and PHY */
#define MISC_RESET_MAC_PHY 0x00000000
#define DEFAULT_MISC MISC_NORMAL
#define MACID0 (CMD_BASE + 0x0070)
#define MACID1 (CMD_BASE + 0x0074)
#define MACID2 (CMD_BASE + 0x0078)
#define TXLEN (CMD_BASE + 0x007C)
#define DEFAULT_TXLEN 0x000005FC
#define RXFILTER (CMD_BASE + 0x0080)
#define RX_RXANY 0x00000001
#define RX_MULTICAST 0x00000002
#define RX_UNICAST 0x00000004
#define RX_BROADCAST 0x00000008
#define RX_MULTI_HASH 0x00000010
#define DISABLE_RXFILTER 0x00000000
#define DEFAULT_RXFILTER (RX_BROADCAST + RX_UNICAST)
#define MDIOCTRL (CMD_BASE + 0x0084)
#define PHY_ADDR_MASK 0x0000001F
#define REG_ADDR_MASK 0x00001F00
#define READ_PHY 0x00004000
#define WRITE_PHY 0x00008000
#define MDIODP (CMD_BASE + 0x0088)
#define GPIOCTRL (CMD_BASE + 0x008C)
#define RXINDICATOR (CMD_BASE + 0x0090)
#define RX_START_READ 0x00000001
#define RX_STOP_READ 0x00000000
#define DEFAULT_RXINDICATOR RX_STOP_READ
#define TXST (CMD_BASE + 0x0094)
#define MDCCLKPAT (CMD_BASE + 0x00A0)
#define RXIPCRCCNT (CMD_BASE + 0x00A4)
#define RXCRCCNT (CMD_BASE + 0x00A8)
#define TXFAILCNT (CMD_BASE + 0x00AC)
#define PROMDP (CMD_BASE + 0x00B0)
#define PROMCTRL (CMD_BASE + 0x00B4)
#define RELOAD_EEPROM 0x00000200
#define MAXRXLEN (CMD_BASE + 0x00B8)
#define HASHTAB0 (CMD_BASE + 0x00C0)
#define HASHTAB1 (CMD_BASE + 0x00C4)
#define HASHTAB2 (CMD_BASE + 0x00C8)
#define HASHTAB3 (CMD_BASE + 0x00CC)
#define DOGTHD0 (CMD_BASE + 0x00E0)
#define DEFAULT_DOGTHD0 0x0000FFFF
#define DOGTHD1 (CMD_BASE + 0x00E4)
#define START_WATCHDOG_TIMER 0x00008000
#define DEFAULT_DOGTHD1 0x00000FFF
#define SOFTRST (CMD_BASE + 0x00EC)
#define SOFTRST_NORMAL 0x00000003
#define SOFTRST_RESET_MAC 0x00000002
/* External PHY Register Definition */
#define BMCR 0x0000
#define LINE_SPEED_MSB 0x0040
#define DUPLEX_MODE 0x0100
#define RESTART_AUTONEG 0x0200
#define POWER_DOWN 0x0800
#define AUTONEG_EN 0x1000
#define LINE_SPEED_LSB 0x2000
#define PHY_RESET 0x8000
#define MEDIAMODE_MASK (LINE_SPEED_MSB | LINE_SPEED_LSB |\
DUPLEX_MODE)
#define BMCR_SPEED_1000 LINE_SPEED_MSB
#define BMCR_SPEED_100 LINE_SPEED_LSB
#define BMCR_SPEED_10 0x0000
#define BMCR_1000FULL (BMCR_SPEED_1000 | DUPLEX_MODE)
#define BMCR_100FULL (BMCR_SPEED_100 | DUPLEX_MODE)
#define BMCR_100HALF BMCR_SPEED_100
#define BMCR_10FULL DUPLEX_MODE
#define BMCR_10HALF 0x0000
#define BMSR 0x0001
#define LINKOK 0x0004
#define AUTONEG_ENABLE_STS 0x0008
#define AUTONEG_COMPLETE 0x0020
#define PHYIDR0 0x0002
#define PHYIDR1 0x0003
#define ANAR 0x0004
#define ANAR_PAUSE 0x0400
#define ANAR_100FULL 0x0100
#define ANAR_100HALF 0x0080
#define ANAR_10FULL 0x0040
#define ANAR_10HALF 0x0020
#define ANAR_8023BIT 0x0001
#define ANLPAR 0x0005
#define ANER 0x0006
#define AUX_1000_CTRL 0x0009
#define ENABLE_1000HALF 0x0100
#define ENABLE_1000FULL 0x0200
#define DEFAULT_AUX_1000_CTRL (ENABLE_1000HALF | ENABLE_1000FULL)
#define AUX_1000_STATUS 0x000A
#define LP_1000HALF 0x0400
#define LP_1000FULL 0x0800
/* Marvell 88E1111 Gigabit PHY Register Definition */
#define M88_SSR 0x0011
#define SSR_SPEED_MASK 0xC000
#define SSR_SPEED_1000 0x8000
#define SSR_SPEED_100 0x4000
#define SSR_SPEED_10 0x0000
#define SSR_DUPLEX 0x2000
#define SSR_MEDIA_RESOLVED_OK 0x0800
#define SSR_MEDIA_MASK (SSR_SPEED_MASK | SSR_DUPLEX)
#define SSR_1000FULL (SSR_SPEED_1000 | SSR_DUPLEX)
#define SSR_1000HALF SSR_SPEED_1000
#define SSR_100FULL (SSR_SPEED_100 | SSR_DUPLEX)
#define SSR_100HALF SSR_SPEED_100
#define SSR_10FULL (SSR_SPEED_10 | SSR_DUPLEX)
#define SSR_10HALF SSR_SPEED_10
#define M88_IER 0x0012
#define LINK_CHANGE_INT 0x0400
#define M88_ISR 0x0013
#define LINK_CHANGE_STATUS 0x0400
#define M88_EXT_SCR 0x0014
#define RGMII_RXCLK_DELAY 0x0080
#define RGMII_TXCLK_DELAY 0x0002
#define DEFAULT_EXT_SCR (RGMII_TXCLK_DELAY | RGMII_RXCLK_DELAY)
#define M88_EXT_SSR 0x001B
#define HWCFG_MODE_MASK 0x000F
#define RGMII_COPPER_MODE 0x000B
/* CICADA CIS8201 Gigabit PHY Register Definition */
#define CIS_IMR 0x0019
#define CIS_INT_ENABLE 0x8000
#define CIS_LINK_CHANGE_INT 0x2000
#define CIS_ISR 0x001A
#define CIS_INT_PENDING 0x8000
#define CIS_LINK_CHANGE_STATUS 0x2000
#define CIS_AUX_CTRL_STATUS 0x001C
#define CIS_AUTONEG_COMPLETE 0x8000
#define CIS_SPEED_MASK 0x0018
#define CIS_SPEED_1000 0x0010
#define CIS_SPEED_100 0x0008
#define CIS_SPEED_10 0x0000
#define CIS_DUPLEX 0x0020
#define CIS_MEDIA_MASK (CIS_SPEED_MASK | CIS_DUPLEX)
#define CIS_1000FULL (CIS_SPEED_1000 | CIS_DUPLEX)
#define CIS_1000HALF CIS_SPEED_1000
#define CIS_100FULL (CIS_SPEED_100 | CIS_DUPLEX)
#define CIS_100HALF CIS_SPEED_100
#define CIS_10FULL (CIS_SPEED_10 | CIS_DUPLEX)
#define CIS_10HALF CIS_SPEED_10
#define CIS_SMI_PRIORITY 0x0004
static
inline
unsigned
short
INW
(
struct
eth_device
*
dev
,
unsigned
long
addr
)
{
return
le16_to_cpu
(
*
(
volatile
unsigned
short
*
)
(
addr
+
dev
->
iobase
));
}
static
inline
void
OUTW
(
struct
eth_device
*
dev
,
unsigned
short
command
,
unsigned
long
addr
)
{
*
(
volatile
unsigned
short
*
)
((
addr
+
dev
->
iobase
))
=
cpu_to_le16
(
command
);
}
/*
Access RXBUFFER_START/TXBUFFER_START to read RX buffer/write TX buffer
*/
#if defined (CONFIG_DRIVER_AX88180_16BIT)
static
inline
unsigned
short
READ_RXBUF
(
struct
eth_device
*
dev
)
{
return
le16_to_cpu
(
*
(
volatile
unsigned
short
*
)
(
RXBUFFER_START
+
dev
->
iobase
));
}
static
inline
void
WRITE_TXBUF
(
struct
eth_device
*
dev
,
unsigned
short
data
)
{
*
(
volatile
unsigned
short
*
)
((
TXBUFFER_START
+
dev
->
iobase
))
=
cpu_to_le16
(
data
);
}
#else
static
inline
unsigned
long
READ_RXBUF
(
struct
eth_device
*
dev
)
{
return
le32_to_cpu
(
*
(
volatile
unsigned
long
*
)
(
RXBUFFER_START
+
dev
->
iobase
));
}
static
inline
void
WRITE_TXBUF
(
struct
eth_device
*
dev
,
unsigned
long
data
)
{
*
(
volatile
unsigned
long
*
)
((
TXBUFFER_START
+
dev
->
iobase
))
=
cpu_to_le32
(
data
);
}
#endif
#endif
/* _AX88180_H_ */
drivers/net/ax88796.c
浏览文件 @
65d4a75f
...
...
@@ -143,7 +143,7 @@ static void ax88796_mac_read(u8 *buff)
}
}
int
get_prom
(
u8
*
mac_addr
)
int
get_prom
(
u8
*
mac_addr
,
u8
*
base_addr
)
{
u8
prom
[
32
];
int
i
;
...
...
drivers/net/ne2000.c
浏览文件 @
65d4a75f
...
...
@@ -74,600 +74,11 @@ Add SNMP
#include <common.h>
#include <command.h>
#include <net.h>
#include <malloc.h>
#define mdelay(n) udelay((n)*1000)
/* forward definition of function used for the uboot interface */
void
uboot_push_packet_len
(
int
len
);
void
uboot_push_tx_done
(
int
key
,
int
val
);
/*
* Debugging details
*
* Set to perms of:
* 0 disables all debug output
* 1 for process debug output
* 2 for added data IO output: get_reg, put_reg
* 4 for packet allocation/free output
* 8 for only startup status, so we can tell we're installed OK
*/
#if 0
#define DEBUG 0xf
#else
#define DEBUG 0
#endif
#if DEBUG & 1
#define DEBUG_FUNCTION() do { printf("%s\n", __FUNCTION__); } while (0)
#define DEBUG_LINE() do { printf("%d\n", __LINE__); } while (0)
#define PRINTK(args...) printf(args)
#else
#define DEBUG_FUNCTION() do {} while(0)
#define DEBUG_LINE() do {} while(0)
#define PRINTK(args...)
#endif
/* NE2000 base header file */
#include "ne2000_base.h"
#if defined(CONFIG_DRIVER_AX88796L)
/* AX88796L support */
#include "ax88796.h"
#else
/* Basic NE2000 chip support */
#include "ne2000.h"
#endif
static
dp83902a_priv_data_t
nic
;
/* just one instance of the card supported */
static
bool
dp83902a_init
(
void
)
{
dp83902a_priv_data_t
*
dp
=
&
nic
;
u8
*
base
;
#if defined(NE2000_BASIC_INIT)
int
i
;
#endif
DEBUG_FUNCTION
();
base
=
dp
->
base
;
if
(
!
base
)
return
false
;
/* No device found */
DEBUG_LINE
();
#if defined(NE2000_BASIC_INIT)
/* AX88796L doesn't need */
/* Prepare ESA */
DP_OUT
(
base
,
DP_CR
,
DP_CR_NODMA
|
DP_CR_PAGE1
);
/* Select page 1 */
/* Use the address from the serial EEPROM */
for
(
i
=
0
;
i
<
6
;
i
++
)
DP_IN
(
base
,
DP_P1_PAR0
+
i
,
dp
->
esa
[
i
]);
DP_OUT
(
base
,
DP_CR
,
DP_CR_NODMA
|
DP_CR_PAGE0
);
/* Select page 0 */
printf
(
"NE2000 - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x
\n
"
,
"eeprom"
,
dp
->
esa
[
0
],
dp
->
esa
[
1
],
dp
->
esa
[
2
],
dp
->
esa
[
3
],
dp
->
esa
[
4
],
dp
->
esa
[
5
]
);
#endif
/* NE2000_BASIC_INIT */
return
true
;
}
static
void
dp83902a_stop
(
void
)
{
dp83902a_priv_data_t
*
dp
=
&
nic
;
u8
*
base
=
dp
->
base
;
DEBUG_FUNCTION
();
DP_OUT
(
base
,
DP_CR
,
DP_CR_PAGE0
|
DP_CR_NODMA
|
DP_CR_STOP
);
/* Brutal */
DP_OUT
(
base
,
DP_ISR
,
0xFF
);
/* Clear any pending interrupts */
DP_OUT
(
base
,
DP_IMR
,
0x00
);
/* Disable all interrupts */
dp
->
running
=
false
;
}
/*
* This function is called to "start up" the interface. It may be called
* multiple times, even when the hardware is already running. It will be
* called whenever something "hardware oriented" changes and should leave
* the hardware ready to send/receive packets.
*/
static
void
dp83902a_start
(
u8
*
enaddr
)
{
dp83902a_priv_data_t
*
dp
=
&
nic
;
u8
*
base
=
dp
->
base
;
int
i
;
DEBUG_FUNCTION
();
DP_OUT
(
base
,
DP_CR
,
DP_CR_PAGE0
|
DP_CR_NODMA
|
DP_CR_STOP
);
/* Brutal */
DP_OUT
(
base
,
DP_DCR
,
DP_DCR_INIT
);
DP_OUT
(
base
,
DP_RBCH
,
0
);
/* Remote byte count */
DP_OUT
(
base
,
DP_RBCL
,
0
);
DP_OUT
(
base
,
DP_RCR
,
DP_RCR_MON
);
/* Accept no packets */
DP_OUT
(
base
,
DP_TCR
,
DP_TCR_LOCAL
);
/* Transmitter [virtually] off */
DP_OUT
(
base
,
DP_TPSR
,
dp
->
tx_buf1
);
/* Transmitter start page */
dp
->
tx1
=
dp
->
tx2
=
0
;
dp
->
tx_next
=
dp
->
tx_buf1
;
dp
->
tx_started
=
false
;
dp
->
running
=
true
;
DP_OUT
(
base
,
DP_PSTART
,
dp
->
rx_buf_start
);
/* Receive ring start page */
DP_OUT
(
base
,
DP_BNDRY
,
dp
->
rx_buf_end
-
1
);
/* Receive ring boundary */
DP_OUT
(
base
,
DP_PSTOP
,
dp
->
rx_buf_end
);
/* Receive ring end page */
dp
->
rx_next
=
dp
->
rx_buf_start
-
1
;
dp
->
running
=
true
;
DP_OUT
(
base
,
DP_ISR
,
0xFF
);
/* Clear any pending interrupts */
DP_OUT
(
base
,
DP_IMR
,
DP_IMR_All
);
/* Enable all interrupts */
DP_OUT
(
base
,
DP_CR
,
DP_CR_NODMA
|
DP_CR_PAGE1
|
DP_CR_STOP
);
/* Select page 1 */
DP_OUT
(
base
,
DP_P1_CURP
,
dp
->
rx_buf_start
);
/* Current page - next free page for Rx */
dp
->
running
=
true
;
for
(
i
=
0
;
i
<
ETHER_ADDR_LEN
;
i
++
)
{
/* FIXME */
/*((vu_short*)( base + ((DP_P1_PAR0 + i) * 2) +
* 0x1400)) = enaddr[i];*/
DP_OUT
(
base
,
DP_P1_PAR0
+
i
,
enaddr
[
i
]);
}
/* Enable and start device */
DP_OUT
(
base
,
DP_CR
,
DP_CR_PAGE0
|
DP_CR_NODMA
|
DP_CR_START
);
DP_OUT
(
base
,
DP_TCR
,
DP_TCR_NORMAL
);
/* Normal transmit operations */
DP_OUT
(
base
,
DP_RCR
,
DP_RCR_AB
);
/* Accept broadcast, no errors, no multicast */
dp
->
running
=
true
;
}
/*
* This routine is called to start the transmitter. It is split out from the
* data handling routine so it may be called either when data becomes first
* available or when an Tx interrupt occurs
*/
static
void
dp83902a_start_xmit
(
int
start_page
,
int
len
)
{
dp83902a_priv_data_t
*
dp
=
(
dp83902a_priv_data_t
*
)
&
nic
;
u8
*
base
=
dp
->
base
;
DEBUG_FUNCTION
();
#if DEBUG & 1
printf
(
"Tx pkt %d len %d
\n
"
,
start_page
,
len
);
if
(
dp
->
tx_started
)
printf
(
"TX already started?!?
\n
"
);
#endif
DP_OUT
(
base
,
DP_ISR
,
(
DP_ISR_TxP
|
DP_ISR_TxE
));
DP_OUT
(
base
,
DP_CR
,
DP_CR_PAGE0
|
DP_CR_NODMA
|
DP_CR_START
);
DP_OUT
(
base
,
DP_TBCL
,
len
&
0xFF
);
DP_OUT
(
base
,
DP_TBCH
,
len
>>
8
);
DP_OUT
(
base
,
DP_TPSR
,
start_page
);
DP_OUT
(
base
,
DP_CR
,
DP_CR_NODMA
|
DP_CR_TXPKT
|
DP_CR_START
);
dp
->
tx_started
=
true
;
}
/*
* This routine is called to send data to the hardware. It is known a-priori
* that there is free buffer space (dp->tx_next).
*/
static
void
dp83902a_send
(
u8
*
data
,
int
total_len
,
u32
key
)
{
struct
dp83902a_priv_data
*
dp
=
(
struct
dp83902a_priv_data
*
)
&
nic
;
u8
*
base
=
dp
->
base
;
int
len
,
start_page
,
pkt_len
,
i
,
isr
;
#if DEBUG & 4
int
dx
;
#endif
DEBUG_FUNCTION
();
len
=
pkt_len
=
total_len
;
if
(
pkt_len
<
IEEE_8023_MIN_FRAME
)
pkt_len
=
IEEE_8023_MIN_FRAME
;
start_page
=
dp
->
tx_next
;
if
(
dp
->
tx_next
==
dp
->
tx_buf1
)
{
dp
->
tx1
=
start_page
;
dp
->
tx1_len
=
pkt_len
;
dp
->
tx1_key
=
key
;
dp
->
tx_next
=
dp
->
tx_buf2
;
}
else
{
dp
->
tx2
=
start_page
;
dp
->
tx2_len
=
pkt_len
;
dp
->
tx2_key
=
key
;
dp
->
tx_next
=
dp
->
tx_buf1
;
}
#if DEBUG & 5
printf
(
"TX prep page %d len %d
\n
"
,
start_page
,
pkt_len
);
#endif
DP_OUT
(
base
,
DP_ISR
,
DP_ISR_RDC
);
/* Clear end of DMA */
{
/*
* Dummy read. The manual sez something slightly different,
* but the code is extended a bit to do what Hitachi's monitor
* does (i.e., also read data).
*/
u16
tmp
;
int
len
=
1
;
DP_OUT
(
base
,
DP_RSAL
,
0x100
-
len
);
DP_OUT
(
base
,
DP_RSAH
,
(
start_page
-
1
)
&
0xff
);
DP_OUT
(
base
,
DP_RBCL
,
len
);
DP_OUT
(
base
,
DP_RBCH
,
0
);
DP_OUT
(
base
,
DP_CR
,
DP_CR_PAGE0
|
DP_CR_RDMA
|
DP_CR_START
);
DP_IN_DATA
(
dp
->
data
,
tmp
);
}
#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
/*
* Stall for a bit before continuing to work around random data
* corruption problems on some platforms.
*/
CYGACC_CALL_IF_DELAY_US
(
1
);
#endif
/* Send data to device buffer(s) */
DP_OUT
(
base
,
DP_RSAL
,
0
);
DP_OUT
(
base
,
DP_RSAH
,
start_page
);
DP_OUT
(
base
,
DP_RBCL
,
pkt_len
&
0xFF
);
DP_OUT
(
base
,
DP_RBCH
,
pkt_len
>>
8
);
DP_OUT
(
base
,
DP_CR
,
DP_CR_WDMA
|
DP_CR_START
);
/* Put data into buffer */
#if DEBUG & 4
printf
(
" sg buf %08lx len %08x
\n
"
,
(
u32
)
data
,
len
);
dx
=
0
;
#endif
while
(
len
>
0
)
{
#if DEBUG & 4
printf
(
" %02x"
,
*
data
);
if
(
0
==
(
++
dx
%
16
))
printf
(
"
\n
"
);
#endif
DP_OUT_DATA
(
dp
->
data
,
*
data
++
);
len
--
;
}
#if DEBUG & 4
printf
(
"
\n
"
);
#endif
if
(
total_len
<
pkt_len
)
{
#if DEBUG & 4
printf
(
" + %d bytes of padding
\n
"
,
pkt_len
-
total_len
);
#endif
/* Padding to 802.3 length was required */
for
(
i
=
total_len
;
i
<
pkt_len
;)
{
i
++
;
DP_OUT_DATA
(
dp
->
data
,
0
);
}
}
#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
/*
* After last data write, delay for a bit before accessing the
* device again, or we may get random data corruption in the last
* datum (on some platforms).
*/
CYGACC_CALL_IF_DELAY_US
(
1
);
#endif
/* Wait for DMA to complete */
do
{
DP_IN
(
base
,
DP_ISR
,
isr
);
}
while
((
isr
&
DP_ISR_RDC
)
==
0
);
/* Then disable DMA */
DP_OUT
(
base
,
DP_CR
,
DP_CR_PAGE0
|
DP_CR_NODMA
|
DP_CR_START
);
/* Start transmit if not already going */
if
(
!
dp
->
tx_started
)
{
if
(
start_page
==
dp
->
tx1
)
{
dp
->
tx_int
=
1
;
/* Expecting interrupt from BUF1 */
}
else
{
dp
->
tx_int
=
2
;
/* Expecting interrupt from BUF2 */
}
dp83902a_start_xmit
(
start_page
,
pkt_len
);
}
}
/*
* This function is called when a packet has been received. It's job is
* to prepare to unload the packet from the hardware. Once the length of
* the packet is known, the upper layer of the driver can be told. When
* the upper layer is ready to unload the packet, the internal function
* 'dp83902a_recv' will be called to actually fetch it from the hardware.
*/
static
void
dp83902a_RxEvent
(
void
)
{
struct
dp83902a_priv_data
*
dp
=
(
struct
dp83902a_priv_data
*
)
&
nic
;
u8
*
base
=
dp
->
base
;
u8
rsr
;
u8
rcv_hdr
[
4
];
int
i
,
len
,
pkt
,
cur
;
DEBUG_FUNCTION
();
DP_IN
(
base
,
DP_RSR
,
rsr
);
while
(
true
)
{
/* Read incoming packet header */
DP_OUT
(
base
,
DP_CR
,
DP_CR_PAGE1
|
DP_CR_NODMA
|
DP_CR_START
);
DP_IN
(
base
,
DP_P1_CURP
,
cur
);
DP_OUT
(
base
,
DP_P1_CR
,
DP_CR_PAGE0
|
DP_CR_NODMA
|
DP_CR_START
);
DP_IN
(
base
,
DP_BNDRY
,
pkt
);
pkt
+=
1
;
if
(
pkt
==
dp
->
rx_buf_end
)
pkt
=
dp
->
rx_buf_start
;
if
(
pkt
==
cur
)
{
break
;
}
DP_OUT
(
base
,
DP_RBCL
,
sizeof
(
rcv_hdr
));
DP_OUT
(
base
,
DP_RBCH
,
0
);
DP_OUT
(
base
,
DP_RSAL
,
0
);
DP_OUT
(
base
,
DP_RSAH
,
pkt
);
if
(
dp
->
rx_next
==
pkt
)
{
if
(
cur
==
dp
->
rx_buf_start
)
DP_OUT
(
base
,
DP_BNDRY
,
dp
->
rx_buf_end
-
1
);
else
DP_OUT
(
base
,
DP_BNDRY
,
cur
-
1
);
/* Update pointer */
return
;
}
dp
->
rx_next
=
pkt
;
DP_OUT
(
base
,
DP_ISR
,
DP_ISR_RDC
);
/* Clear end of DMA */
DP_OUT
(
base
,
DP_CR
,
DP_CR_RDMA
|
DP_CR_START
);
#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
CYGACC_CALL_IF_DELAY_US
(
10
);
#endif
/* read header (get data size)*/
for
(
i
=
0
;
i
<
sizeof
(
rcv_hdr
);)
{
DP_IN_DATA
(
dp
->
data
,
rcv_hdr
[
i
++
]);
}
#if DEBUG & 5
printf
(
"rx hdr %02x %02x %02x %02x
\n
"
,
rcv_hdr
[
0
],
rcv_hdr
[
1
],
rcv_hdr
[
2
],
rcv_hdr
[
3
]);
#endif
len
=
((
rcv_hdr
[
3
]
<<
8
)
|
rcv_hdr
[
2
])
-
sizeof
(
rcv_hdr
);
/* data read */
uboot_push_packet_len
(
len
);
if
(
rcv_hdr
[
1
]
==
dp
->
rx_buf_start
)
DP_OUT
(
base
,
DP_BNDRY
,
dp
->
rx_buf_end
-
1
);
else
DP_OUT
(
base
,
DP_BNDRY
,
rcv_hdr
[
1
]
-
1
);
/* Update pointer */
}
}
/*
* This function is called as a result of the "eth_drv_recv()" call above.
* It's job is to actually fetch data for a packet from the hardware once
* memory buffers have been allocated for the packet. Note that the buffers
* may come in pieces, using a scatter-gather list. This allows for more
* efficient processing in the upper layers of the stack.
*/
static
void
dp83902a_recv
(
u8
*
data
,
int
len
)
{
struct
dp83902a_priv_data
*
dp
=
(
struct
dp83902a_priv_data
*
)
&
nic
;
u8
*
base
=
dp
->
base
;
int
i
,
mlen
;
u8
saved_char
=
0
;
bool
saved
;
#if DEBUG & 4
int
dx
;
#endif
DEBUG_FUNCTION
();
#if DEBUG & 5
printf
(
"Rx packet %d length %d
\n
"
,
dp
->
rx_next
,
len
);
#endif
/* Read incoming packet data */
DP_OUT
(
base
,
DP_CR
,
DP_CR_PAGE0
|
DP_CR_NODMA
|
DP_CR_START
);
DP_OUT
(
base
,
DP_RBCL
,
len
&
0xFF
);
DP_OUT
(
base
,
DP_RBCH
,
len
>>
8
);
DP_OUT
(
base
,
DP_RSAL
,
4
);
/* Past header */
DP_OUT
(
base
,
DP_RSAH
,
dp
->
rx_next
);
DP_OUT
(
base
,
DP_ISR
,
DP_ISR_RDC
);
/* Clear end of DMA */
DP_OUT
(
base
,
DP_CR
,
DP_CR_RDMA
|
DP_CR_START
);
#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
CYGACC_CALL_IF_DELAY_US
(
10
);
#endif
saved
=
false
;
for
(
i
=
0
;
i
<
1
;
i
++
)
{
if
(
data
)
{
mlen
=
len
;
#if DEBUG & 4
printf
(
" sg buf %08lx len %08x
\n
"
,
(
u32
)
data
,
mlen
);
dx
=
0
;
#endif
while
(
0
<
mlen
)
{
/* Saved byte from previous loop? */
if
(
saved
)
{
*
data
++
=
saved_char
;
mlen
--
;
saved
=
false
;
continue
;
}
{
u8
tmp
;
DP_IN_DATA
(
dp
->
data
,
tmp
);
#if DEBUG & 4
printf
(
" %02x"
,
tmp
);
if
(
0
==
(
++
dx
%
16
))
printf
(
"
\n
"
);
#endif
*
data
++
=
tmp
;;
mlen
--
;
}
}
#if DEBUG & 4
printf
(
"
\n
"
);
#endif
}
}
}
static
void
dp83902a_TxEvent
(
void
)
{
struct
dp83902a_priv_data
*
dp
=
(
struct
dp83902a_priv_data
*
)
&
nic
;
u8
*
base
=
dp
->
base
;
u8
tsr
;
u32
key
;
DEBUG_FUNCTION
();
DP_IN
(
base
,
DP_TSR
,
tsr
);
if
(
dp
->
tx_int
==
1
)
{
key
=
dp
->
tx1_key
;
dp
->
tx1
=
0
;
}
else
{
key
=
dp
->
tx2_key
;
dp
->
tx2
=
0
;
}
/* Start next packet if one is ready */
dp
->
tx_started
=
false
;
if
(
dp
->
tx1
)
{
dp83902a_start_xmit
(
dp
->
tx1
,
dp
->
tx1_len
);
dp
->
tx_int
=
1
;
}
else
if
(
dp
->
tx2
)
{
dp83902a_start_xmit
(
dp
->
tx2
,
dp
->
tx2_len
);
dp
->
tx_int
=
2
;
}
else
{
dp
->
tx_int
=
0
;
}
/* Tell higher level we sent this packet */
uboot_push_tx_done
(
key
,
0
);
}
/*
* Read the tally counters to clear them. Called in response to a CNT
* interrupt.
*/
static
void
dp83902a_ClearCounters
(
void
)
{
struct
dp83902a_priv_data
*
dp
=
(
struct
dp83902a_priv_data
*
)
&
nic
;
u8
*
base
=
dp
->
base
;
u8
cnt1
,
cnt2
,
cnt3
;
DP_IN
(
base
,
DP_FER
,
cnt1
);
DP_IN
(
base
,
DP_CER
,
cnt2
);
DP_IN
(
base
,
DP_MISSED
,
cnt3
);
DP_OUT
(
base
,
DP_ISR
,
DP_ISR_CNT
);
}
/*
* Deal with an overflow condition. This code follows the procedure set
* out in section 7.0 of the datasheet.
*/
static
void
dp83902a_Overflow
(
void
)
{
struct
dp83902a_priv_data
*
dp
=
(
struct
dp83902a_priv_data
*
)
&
nic
;
u8
*
base
=
dp
->
base
;
u8
isr
;
/* Issue a stop command and wait 1.6ms for it to complete. */
DP_OUT
(
base
,
DP_CR
,
DP_CR_STOP
|
DP_CR_NODMA
);
CYGACC_CALL_IF_DELAY_US
(
1600
);
/* Clear the remote byte counter registers. */
DP_OUT
(
base
,
DP_RBCL
,
0
);
DP_OUT
(
base
,
DP_RBCH
,
0
);
/* Enter loopback mode while we clear the buffer. */
DP_OUT
(
base
,
DP_TCR
,
DP_TCR_LOCAL
);
DP_OUT
(
base
,
DP_CR
,
DP_CR_START
|
DP_CR_NODMA
);
/*
* Read in as many packets as we can and acknowledge any and receive
* interrupts. Since the buffer has overflowed, a receive event of
* some kind will have occured.
*/
dp83902a_RxEvent
();
DP_OUT
(
base
,
DP_ISR
,
DP_ISR_RxP
|
DP_ISR_RxE
);
/* Clear the overflow condition and leave loopback mode. */
DP_OUT
(
base
,
DP_ISR
,
DP_ISR_OFLW
);
DP_OUT
(
base
,
DP_TCR
,
DP_TCR_NORMAL
);
/*
* If a transmit command was issued, but no transmit event has occured,
* restart it here.
*/
DP_IN
(
base
,
DP_ISR
,
isr
);
if
(
dp
->
tx_started
&&
!
(
isr
&
(
DP_ISR_TxP
|
DP_ISR_TxE
)))
{
DP_OUT
(
base
,
DP_CR
,
DP_CR_NODMA
|
DP_CR_TXPKT
|
DP_CR_START
);
}
}
static
void
dp83902a_poll
(
void
)
{
struct
dp83902a_priv_data
*
dp
=
(
struct
dp83902a_priv_data
*
)
&
nic
;
u8
*
base
=
dp
->
base
;
u8
isr
;
DP_OUT
(
base
,
DP_CR
,
DP_CR_NODMA
|
DP_CR_PAGE0
|
DP_CR_START
);
DP_IN
(
base
,
DP_ISR
,
isr
);
while
(
0
!=
isr
)
{
/*
* The CNT interrupt triggers when the MSB of one of the error
* counters is set. We don't much care about these counters, but
* we should read their values to reset them.
*/
if
(
isr
&
DP_ISR_CNT
)
{
dp83902a_ClearCounters
();
}
/*
* Check for overflow. It's a special case, since there's a
* particular procedure that must be followed to get back into
* a running state.a
*/
if
(
isr
&
DP_ISR_OFLW
)
{
dp83902a_Overflow
();
}
else
{
/*
* Other kinds of interrupts can be acknowledged simply by
* clearing the relevant bits of the ISR. Do that now, then
* handle the interrupts we care about.
*/
DP_OUT
(
base
,
DP_ISR
,
isr
);
/* Clear set bits */
if
(
!
dp
->
running
)
break
;
/* Is this necessary? */
/*
* Check for tx_started on TX event since these may happen
* spuriously it seems.
*/
if
(
isr
&
(
DP_ISR_TxP
|
DP_ISR_TxE
)
&&
dp
->
tx_started
)
{
dp83902a_TxEvent
();
}
if
(
isr
&
(
DP_ISR_RxP
|
DP_ISR_RxE
))
{
dp83902a_RxEvent
();
}
}
DP_IN
(
base
,
DP_ISR
,
isr
);
}
}
#define mdelay(n) udelay((n)*1000)
/* find prom (taken from pc_net_cs.c from Linux) */
#include "8390.h"
...
...
@@ -763,18 +174,16 @@ static hw_info_t hw_info[] = {
#define PCNET_RESET 0x1f
/* Issue a read to reset, a write to clear. */
#define PCNET_MISC 0x18
/* For IBM CCAE and Socket EA cards */
static
void
pcnet_reset_8390
(
void
)
static
void
pcnet_reset_8390
(
u8
*
addr
)
{
int
i
,
r
;
PRINTK
(
"nic base is %lx
\n
"
,
nic
.
base
);
n2k_outb
(
E8390_NODMA
+
E8390_PAGE0
+
E8390_STOP
,
E8390_CMD
);
PRINTK
(
"cmd (at %lx) is %x
\n
"
,
nic
.
base
+
E8390_CMD
,
n2k_inb
(
E8390_CMD
));
PRINTK
(
"cmd (at %lx) is %x
\n
"
,
addr
+
E8390_CMD
,
n2k_inb
(
E8390_CMD
));
n2k_outb
(
E8390_NODMA
+
E8390_PAGE1
+
E8390_STOP
,
E8390_CMD
);
PRINTK
(
"cmd (at %lx) is %x
\n
"
,
nic
.
base
+
E8390_CMD
,
n2k_inb
(
E8390_CMD
));
PRINTK
(
"cmd (at %lx) is %x
\n
"
,
addr
+
E8390_CMD
,
n2k_inb
(
E8390_CMD
));
n2k_outb
(
E8390_NODMA
+
E8390_PAGE0
+
E8390_STOP
,
E8390_CMD
);
PRINTK
(
"cmd (at %lx) is %x
\n
"
,
nic
.
base
+
E8390_CMD
,
n2k_inb
(
E8390_CMD
));
PRINTK
(
"cmd (at %lx) is %x
\n
"
,
addr
+
E8390_CMD
,
n2k_inb
(
E8390_CMD
));
n2k_outb
(
E8390_NODMA
+
E8390_PAGE0
+
E8390_STOP
,
E8390_CMD
);
n2k_outb
(
n2k_inb
(
PCNET_RESET
),
PCNET_RESET
);
...
...
@@ -791,8 +200,7 @@ static void pcnet_reset_8390(void)
printf
(
"pcnet_reset_8390() did not complete.
\n
"
);
}
/* pcnet_reset_8390 */
int
get_prom
(
u8
*
mac_addr
)
__attribute__
((
weak
,
alias
(
"__get_prom"
)));
int
__get_prom
(
u8
*
mac_addr
)
int
get_prom
(
u8
*
mac_addr
,
u8
*
base_addr
)
{
u8
prom
[
32
];
int
i
,
j
;
...
...
@@ -816,7 +224,7 @@ int __get_prom(u8* mac_addr)
PRINTK
(
"trying to get MAC via prom reading
\n
"
);
pcnet_reset_8390
();
pcnet_reset_8390
(
base_addr
);
mdelay
(
10
);
...
...
@@ -849,116 +257,3 @@ int __get_prom(u8* mac_addr)
}
return
0
;
}
/* U-boot specific routines */
static
u8
*
pbuf
=
NULL
;
static
int
pkey
=
-
1
;
static
int
initialized
=
0
;
void
uboot_push_packet_len
(
int
len
)
{
PRINTK
(
"pushed len = %d
\n
"
,
len
);
if
(
len
>=
2000
)
{
printf
(
"NE2000: packet too big
\n
"
);
return
;
}
dp83902a_recv
(
&
pbuf
[
0
],
len
);
/*Just pass it to the upper layer*/
NetReceive
(
&
pbuf
[
0
],
len
);
}
void
uboot_push_tx_done
(
int
key
,
int
val
)
{
PRINTK
(
"pushed key = %d
\n
"
,
key
);
pkey
=
key
;
}
int
eth_init
(
bd_t
*
bd
)
{
int
r
;
u8
dev_addr
[
6
];
char
ethaddr
[
20
];
PRINTK
(
"### eth_init
\n
"
);
if
(
!
pbuf
)
{
pbuf
=
malloc
(
2000
);
if
(
!
pbuf
)
{
printf
(
"Cannot allocate rx buffer
\n
"
);
return
-
1
;
}
}
#ifdef CONFIG_DRIVER_NE2000_CCR
{
vu_char
*
p
=
(
vu_char
*
)
CONFIG_DRIVER_NE2000_CCR
;
PRINTK
(
"CCR before is %x
\n
"
,
*
p
);
*
p
=
CONFIG_DRIVER_NE2000_VAL
;
PRINTK
(
"CCR after is %x
\n
"
,
*
p
);
}
#endif
nic
.
base
=
(
u8
*
)
CONFIG_DRIVER_NE2000_BASE
;
r
=
get_prom
(
dev_addr
);
if
(
!
r
)
return
-
1
;
sprintf
(
ethaddr
,
"%02X:%02X:%02X:%02X:%02X:%02X"
,
dev_addr
[
0
],
dev_addr
[
1
],
dev_addr
[
2
],
dev_addr
[
3
],
dev_addr
[
4
],
dev_addr
[
5
])
;
PRINTK
(
"Set environment from HW MAC addr =
\"
%s
\"\n
"
,
ethaddr
);
setenv
(
"ethaddr"
,
ethaddr
);
nic
.
data
=
nic
.
base
+
DP_DATA
;
nic
.
tx_buf1
=
START_PG
;
nic
.
tx_buf2
=
START_PG2
;
nic
.
rx_buf_start
=
RX_START
;
nic
.
rx_buf_end
=
RX_END
;
if
(
dp83902a_init
()
==
false
)
return
-
1
;
dp83902a_start
(
dev_addr
);
initialized
=
1
;
return
0
;
}
void
eth_halt
()
{
PRINTK
(
"### eth_halt
\n
"
);
if
(
initialized
)
dp83902a_stop
();
initialized
=
0
;
}
int
eth_rx
()
{
dp83902a_poll
();
return
1
;
}
int
eth_send
(
volatile
void
*
packet
,
int
length
)
{
int
tmo
;
PRINTK
(
"### eth_send
\n
"
);
pkey
=
-
1
;
dp83902a_send
((
u8
*
)
packet
,
length
,
666
);
tmo
=
get_timer
(
0
)
+
TOUT
*
CFG_HZ
;
while
(
1
)
{
dp83902a_poll
();
if
(
pkey
!=
-
1
)
{
PRINTK
(
"Packet sucesfully sent
\n
"
);
return
0
;
}
if
(
get_timer
(
0
)
>=
tmo
)
{
printf
(
"transmission error (timoeut)
\n
"
);
return
0
;
}
}
return
0
;
}
drivers/net/ne2000_base.c
0 → 100644
浏览文件 @
65d4a75f
/*
Ported to U-Boot by Christian Pellegrin <chri@ascensit.com>
Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and
eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world
are GPL, so this is, of course, GPL.
==========================================================================
dev/if_dp83902a.c
Ethernet device driver for NS DP83902a ethernet controller
==========================================================================
####ECOSGPLCOPYRIGHTBEGIN####
-------------------------------------------
This file is part of eCos, the Embedded Configurable Operating System.
Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
eCos is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 or (at your option) any later version.
eCos is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with eCos; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
As a special exception, if other files instantiate templates or use macros
or inline functions from this file, or you compile this file and link it
with other works to produce a work based on this file, this file does not
by itself cause the resulting work to be covered by the GNU General Public
License. However the source code for this file must still be made available
in accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work based on
this file might be covered by the GNU General Public License.
Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
at http://sources.redhat.com/ecos/ecos-license/
-------------------------------------------
####ECOSGPLCOPYRIGHTEND####
####BSDCOPYRIGHTBEGIN####
-------------------------------------------
Portions of this software may have been derived from OpenBSD or other sources,
and are covered by the appropriate copyright disclaimers included herein.
-------------------------------------------
####BSDCOPYRIGHTEND####
==========================================================================
#####DESCRIPTIONBEGIN####
Author(s): gthomas
Contributors: gthomas, jskov, rsandifo
Date: 2001-06-13
Purpose:
Description:
FIXME: Will fail if pinged with large packets (1520 bytes)
Add promisc config
Add SNMP
####DESCRIPTIONEND####
==========================================================================
*/
#include <common.h>
#include <command.h>
#include <net.h>
#include <malloc.h>
#define mdelay(n) udelay((n)*1000)
/* forward definition of function used for the uboot interface */
void
uboot_push_packet_len
(
int
len
);
void
uboot_push_tx_done
(
int
key
,
int
val
);
/* NE2000 base header file */
#include "ne2000_base.h"
#if defined(CONFIG_DRIVER_AX88796L)
/* AX88796L support */
#include "ax88796.h"
#else
/* Basic NE2000 chip support */
#include "ne2000.h"
#endif
static
dp83902a_priv_data_t
nic
;
/* just one instance of the card supported */
static
bool
dp83902a_init
(
void
)
{
dp83902a_priv_data_t
*
dp
=
&
nic
;
u8
*
base
;
#if defined(NE2000_BASIC_INIT)
int
i
;
#endif
DEBUG_FUNCTION
();
base
=
dp
->
base
;
if
(
!
base
)
return
false
;
/* No device found */
DEBUG_LINE
();
#if defined(NE2000_BASIC_INIT)
/* AX88796L doesn't need */
/* Prepare ESA */
DP_OUT
(
base
,
DP_CR
,
DP_CR_NODMA
|
DP_CR_PAGE1
);
/* Select page 1 */
/* Use the address from the serial EEPROM */
for
(
i
=
0
;
i
<
6
;
i
++
)
DP_IN
(
base
,
DP_P1_PAR0
+
i
,
dp
->
esa
[
i
]);
DP_OUT
(
base
,
DP_CR
,
DP_CR_NODMA
|
DP_CR_PAGE0
);
/* Select page 0 */
printf
(
"NE2000 - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x
\n
"
,
"eeprom"
,
dp
->
esa
[
0
],
dp
->
esa
[
1
],
dp
->
esa
[
2
],
dp
->
esa
[
3
],
dp
->
esa
[
4
],
dp
->
esa
[
5
]
);
#endif
/* NE2000_BASIC_INIT */
return
true
;
}
static
void
dp83902a_stop
(
void
)
{
dp83902a_priv_data_t
*
dp
=
&
nic
;
u8
*
base
=
dp
->
base
;
DEBUG_FUNCTION
();
DP_OUT
(
base
,
DP_CR
,
DP_CR_PAGE0
|
DP_CR_NODMA
|
DP_CR_STOP
);
/* Brutal */
DP_OUT
(
base
,
DP_ISR
,
0xFF
);
/* Clear any pending interrupts */
DP_OUT
(
base
,
DP_IMR
,
0x00
);
/* Disable all interrupts */
dp
->
running
=
false
;
}
/*
* This function is called to "start up" the interface. It may be called
* multiple times, even when the hardware is already running. It will be
* called whenever something "hardware oriented" changes and should leave
* the hardware ready to send/receive packets.
*/
static
void
dp83902a_start
(
u8
*
enaddr
)
{
dp83902a_priv_data_t
*
dp
=
&
nic
;
u8
*
base
=
dp
->
base
;
int
i
;
DEBUG_FUNCTION
();
DP_OUT
(
base
,
DP_CR
,
DP_CR_PAGE0
|
DP_CR_NODMA
|
DP_CR_STOP
);
/* Brutal */
DP_OUT
(
base
,
DP_DCR
,
DP_DCR_INIT
);
DP_OUT
(
base
,
DP_RBCH
,
0
);
/* Remote byte count */
DP_OUT
(
base
,
DP_RBCL
,
0
);
DP_OUT
(
base
,
DP_RCR
,
DP_RCR_MON
);
/* Accept no packets */
DP_OUT
(
base
,
DP_TCR
,
DP_TCR_LOCAL
);
/* Transmitter [virtually] off */
DP_OUT
(
base
,
DP_TPSR
,
dp
->
tx_buf1
);
/* Transmitter start page */
dp
->
tx1
=
dp
->
tx2
=
0
;
dp
->
tx_next
=
dp
->
tx_buf1
;
dp
->
tx_started
=
false
;
dp
->
running
=
true
;
DP_OUT
(
base
,
DP_PSTART
,
dp
->
rx_buf_start
);
/* Receive ring start page */
DP_OUT
(
base
,
DP_BNDRY
,
dp
->
rx_buf_end
-
1
);
/* Receive ring boundary */
DP_OUT
(
base
,
DP_PSTOP
,
dp
->
rx_buf_end
);
/* Receive ring end page */
dp
->
rx_next
=
dp
->
rx_buf_start
-
1
;
dp
->
running
=
true
;
DP_OUT
(
base
,
DP_ISR
,
0xFF
);
/* Clear any pending interrupts */
DP_OUT
(
base
,
DP_IMR
,
DP_IMR_All
);
/* Enable all interrupts */
DP_OUT
(
base
,
DP_CR
,
DP_CR_NODMA
|
DP_CR_PAGE1
|
DP_CR_STOP
);
/* Select page 1 */
DP_OUT
(
base
,
DP_P1_CURP
,
dp
->
rx_buf_start
);
/* Current page - next free page for Rx */
dp
->
running
=
true
;
for
(
i
=
0
;
i
<
ETHER_ADDR_LEN
;
i
++
)
{
/* FIXME */
/*((vu_short*)( base + ((DP_P1_PAR0 + i) * 2) +
* 0x1400)) = enaddr[i];*/
DP_OUT
(
base
,
DP_P1_PAR0
+
i
,
enaddr
[
i
]);
}
/* Enable and start device */
DP_OUT
(
base
,
DP_CR
,
DP_CR_PAGE0
|
DP_CR_NODMA
|
DP_CR_START
);
DP_OUT
(
base
,
DP_TCR
,
DP_TCR_NORMAL
);
/* Normal transmit operations */
DP_OUT
(
base
,
DP_RCR
,
DP_RCR_AB
);
/* Accept broadcast, no errors, no multicast */
dp
->
running
=
true
;
}
/*
* This routine is called to start the transmitter. It is split out from the
* data handling routine so it may be called either when data becomes first
* available or when an Tx interrupt occurs
*/
static
void
dp83902a_start_xmit
(
int
start_page
,
int
len
)
{
dp83902a_priv_data_t
*
dp
=
(
dp83902a_priv_data_t
*
)
&
nic
;
u8
*
base
=
dp
->
base
;
DEBUG_FUNCTION
();
#if DEBUG & 1
printf
(
"Tx pkt %d len %d
\n
"
,
start_page
,
len
);
if
(
dp
->
tx_started
)
printf
(
"TX already started?!?
\n
"
);
#endif
DP_OUT
(
base
,
DP_ISR
,
(
DP_ISR_TxP
|
DP_ISR_TxE
));
DP_OUT
(
base
,
DP_CR
,
DP_CR_PAGE0
|
DP_CR_NODMA
|
DP_CR_START
);
DP_OUT
(
base
,
DP_TBCL
,
len
&
0xFF
);
DP_OUT
(
base
,
DP_TBCH
,
len
>>
8
);
DP_OUT
(
base
,
DP_TPSR
,
start_page
);
DP_OUT
(
base
,
DP_CR
,
DP_CR_NODMA
|
DP_CR_TXPKT
|
DP_CR_START
);
dp
->
tx_started
=
true
;
}
/*
* This routine is called to send data to the hardware. It is known a-priori
* that there is free buffer space (dp->tx_next).
*/
static
void
dp83902a_send
(
u8
*
data
,
int
total_len
,
u32
key
)
{
struct
dp83902a_priv_data
*
dp
=
(
struct
dp83902a_priv_data
*
)
&
nic
;
u8
*
base
=
dp
->
base
;
int
len
,
start_page
,
pkt_len
,
i
,
isr
;
#if DEBUG & 4
int
dx
;
#endif
DEBUG_FUNCTION
();
len
=
pkt_len
=
total_len
;
if
(
pkt_len
<
IEEE_8023_MIN_FRAME
)
pkt_len
=
IEEE_8023_MIN_FRAME
;
start_page
=
dp
->
tx_next
;
if
(
dp
->
tx_next
==
dp
->
tx_buf1
)
{
dp
->
tx1
=
start_page
;
dp
->
tx1_len
=
pkt_len
;
dp
->
tx1_key
=
key
;
dp
->
tx_next
=
dp
->
tx_buf2
;
}
else
{
dp
->
tx2
=
start_page
;
dp
->
tx2_len
=
pkt_len
;
dp
->
tx2_key
=
key
;
dp
->
tx_next
=
dp
->
tx_buf1
;
}
#if DEBUG & 5
printf
(
"TX prep page %d len %d
\n
"
,
start_page
,
pkt_len
);
#endif
DP_OUT
(
base
,
DP_ISR
,
DP_ISR_RDC
);
/* Clear end of DMA */
{
/*
* Dummy read. The manual sez something slightly different,
* but the code is extended a bit to do what Hitachi's monitor
* does (i.e., also read data).
*/
u16
tmp
;
int
len
=
1
;
DP_OUT
(
base
,
DP_RSAL
,
0x100
-
len
);
DP_OUT
(
base
,
DP_RSAH
,
(
start_page
-
1
)
&
0xff
);
DP_OUT
(
base
,
DP_RBCL
,
len
);
DP_OUT
(
base
,
DP_RBCH
,
0
);
DP_OUT
(
base
,
DP_CR
,
DP_CR_PAGE0
|
DP_CR_RDMA
|
DP_CR_START
);
DP_IN_DATA
(
dp
->
data
,
tmp
);
}
#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
/*
* Stall for a bit before continuing to work around random data
* corruption problems on some platforms.
*/
CYGACC_CALL_IF_DELAY_US
(
1
);
#endif
/* Send data to device buffer(s) */
DP_OUT
(
base
,
DP_RSAL
,
0
);
DP_OUT
(
base
,
DP_RSAH
,
start_page
);
DP_OUT
(
base
,
DP_RBCL
,
pkt_len
&
0xFF
);
DP_OUT
(
base
,
DP_RBCH
,
pkt_len
>>
8
);
DP_OUT
(
base
,
DP_CR
,
DP_CR_WDMA
|
DP_CR_START
);
/* Put data into buffer */
#if DEBUG & 4
printf
(
" sg buf %08lx len %08x
\n
"
,
(
u32
)
data
,
len
);
dx
=
0
;
#endif
while
(
len
>
0
)
{
#if DEBUG & 4
printf
(
" %02x"
,
*
data
);
if
(
0
==
(
++
dx
%
16
))
printf
(
"
\n
"
);
#endif
DP_OUT_DATA
(
dp
->
data
,
*
data
++
);
len
--
;
}
#if DEBUG & 4
printf
(
"
\n
"
);
#endif
if
(
total_len
<
pkt_len
)
{
#if DEBUG & 4
printf
(
" + %d bytes of padding
\n
"
,
pkt_len
-
total_len
);
#endif
/* Padding to 802.3 length was required */
for
(
i
=
total_len
;
i
<
pkt_len
;)
{
i
++
;
DP_OUT_DATA
(
dp
->
data
,
0
);
}
}
#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
/*
* After last data write, delay for a bit before accessing the
* device again, or we may get random data corruption in the last
* datum (on some platforms).
*/
CYGACC_CALL_IF_DELAY_US
(
1
);
#endif
/* Wait for DMA to complete */
do
{
DP_IN
(
base
,
DP_ISR
,
isr
);
}
while
((
isr
&
DP_ISR_RDC
)
==
0
);
/* Then disable DMA */
DP_OUT
(
base
,
DP_CR
,
DP_CR_PAGE0
|
DP_CR_NODMA
|
DP_CR_START
);
/* Start transmit if not already going */
if
(
!
dp
->
tx_started
)
{
if
(
start_page
==
dp
->
tx1
)
{
dp
->
tx_int
=
1
;
/* Expecting interrupt from BUF1 */
}
else
{
dp
->
tx_int
=
2
;
/* Expecting interrupt from BUF2 */
}
dp83902a_start_xmit
(
start_page
,
pkt_len
);
}
}
/*
* This function is called when a packet has been received. It's job is
* to prepare to unload the packet from the hardware. Once the length of
* the packet is known, the upper layer of the driver can be told. When
* the upper layer is ready to unload the packet, the internal function
* 'dp83902a_recv' will be called to actually fetch it from the hardware.
*/
static
void
dp83902a_RxEvent
(
void
)
{
struct
dp83902a_priv_data
*
dp
=
(
struct
dp83902a_priv_data
*
)
&
nic
;
u8
*
base
=
dp
->
base
;
u8
rsr
;
u8
rcv_hdr
[
4
];
int
i
,
len
,
pkt
,
cur
;
DEBUG_FUNCTION
();
DP_IN
(
base
,
DP_RSR
,
rsr
);
while
(
true
)
{
/* Read incoming packet header */
DP_OUT
(
base
,
DP_CR
,
DP_CR_PAGE1
|
DP_CR_NODMA
|
DP_CR_START
);
DP_IN
(
base
,
DP_P1_CURP
,
cur
);
DP_OUT
(
base
,
DP_P1_CR
,
DP_CR_PAGE0
|
DP_CR_NODMA
|
DP_CR_START
);
DP_IN
(
base
,
DP_BNDRY
,
pkt
);
pkt
+=
1
;
if
(
pkt
==
dp
->
rx_buf_end
)
pkt
=
dp
->
rx_buf_start
;
if
(
pkt
==
cur
)
{
break
;
}
DP_OUT
(
base
,
DP_RBCL
,
sizeof
(
rcv_hdr
));
DP_OUT
(
base
,
DP_RBCH
,
0
);
DP_OUT
(
base
,
DP_RSAL
,
0
);
DP_OUT
(
base
,
DP_RSAH
,
pkt
);
if
(
dp
->
rx_next
==
pkt
)
{
if
(
cur
==
dp
->
rx_buf_start
)
DP_OUT
(
base
,
DP_BNDRY
,
dp
->
rx_buf_end
-
1
);
else
DP_OUT
(
base
,
DP_BNDRY
,
cur
-
1
);
/* Update pointer */
return
;
}
dp
->
rx_next
=
pkt
;
DP_OUT
(
base
,
DP_ISR
,
DP_ISR_RDC
);
/* Clear end of DMA */
DP_OUT
(
base
,
DP_CR
,
DP_CR_RDMA
|
DP_CR_START
);
#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
CYGACC_CALL_IF_DELAY_US
(
10
);
#endif
/* read header (get data size)*/
for
(
i
=
0
;
i
<
sizeof
(
rcv_hdr
);)
{
DP_IN_DATA
(
dp
->
data
,
rcv_hdr
[
i
++
]);
}
#if DEBUG & 5
printf
(
"rx hdr %02x %02x %02x %02x
\n
"
,
rcv_hdr
[
0
],
rcv_hdr
[
1
],
rcv_hdr
[
2
],
rcv_hdr
[
3
]);
#endif
len
=
((
rcv_hdr
[
3
]
<<
8
)
|
rcv_hdr
[
2
])
-
sizeof
(
rcv_hdr
);
/* data read */
uboot_push_packet_len
(
len
);
if
(
rcv_hdr
[
1
]
==
dp
->
rx_buf_start
)
DP_OUT
(
base
,
DP_BNDRY
,
dp
->
rx_buf_end
-
1
);
else
DP_OUT
(
base
,
DP_BNDRY
,
rcv_hdr
[
1
]
-
1
);
/* Update pointer */
}
}
/*
* This function is called as a result of the "eth_drv_recv()" call above.
* It's job is to actually fetch data for a packet from the hardware once
* memory buffers have been allocated for the packet. Note that the buffers
* may come in pieces, using a scatter-gather list. This allows for more
* efficient processing in the upper layers of the stack.
*/
static
void
dp83902a_recv
(
u8
*
data
,
int
len
)
{
struct
dp83902a_priv_data
*
dp
=
(
struct
dp83902a_priv_data
*
)
&
nic
;
u8
*
base
=
dp
->
base
;
int
i
,
mlen
;
u8
saved_char
=
0
;
bool
saved
;
#if DEBUG & 4
int
dx
;
#endif
DEBUG_FUNCTION
();
#if DEBUG & 5
printf
(
"Rx packet %d length %d
\n
"
,
dp
->
rx_next
,
len
);
#endif
/* Read incoming packet data */
DP_OUT
(
base
,
DP_CR
,
DP_CR_PAGE0
|
DP_CR_NODMA
|
DP_CR_START
);
DP_OUT
(
base
,
DP_RBCL
,
len
&
0xFF
);
DP_OUT
(
base
,
DP_RBCH
,
len
>>
8
);
DP_OUT
(
base
,
DP_RSAL
,
4
);
/* Past header */
DP_OUT
(
base
,
DP_RSAH
,
dp
->
rx_next
);
DP_OUT
(
base
,
DP_ISR
,
DP_ISR_RDC
);
/* Clear end of DMA */
DP_OUT
(
base
,
DP_CR
,
DP_CR_RDMA
|
DP_CR_START
);
#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
CYGACC_CALL_IF_DELAY_US
(
10
);
#endif
saved
=
false
;
for
(
i
=
0
;
i
<
1
;
i
++
)
{
if
(
data
)
{
mlen
=
len
;
#if DEBUG & 4
printf
(
" sg buf %08lx len %08x
\n
"
,
(
u32
)
data
,
mlen
);
dx
=
0
;
#endif
while
(
0
<
mlen
)
{
/* Saved byte from previous loop? */
if
(
saved
)
{
*
data
++
=
saved_char
;
mlen
--
;
saved
=
false
;
continue
;
}
{
u8
tmp
;
DP_IN_DATA
(
dp
->
data
,
tmp
);
#if DEBUG & 4
printf
(
" %02x"
,
tmp
);
if
(
0
==
(
++
dx
%
16
))
printf
(
"
\n
"
);
#endif
*
data
++
=
tmp
;;
mlen
--
;
}
}
#if DEBUG & 4
printf
(
"
\n
"
);
#endif
}
}
}
static
void
dp83902a_TxEvent
(
void
)
{
struct
dp83902a_priv_data
*
dp
=
(
struct
dp83902a_priv_data
*
)
&
nic
;
u8
*
base
=
dp
->
base
;
u8
tsr
;
u32
key
;
DEBUG_FUNCTION
();
DP_IN
(
base
,
DP_TSR
,
tsr
);
if
(
dp
->
tx_int
==
1
)
{
key
=
dp
->
tx1_key
;
dp
->
tx1
=
0
;
}
else
{
key
=
dp
->
tx2_key
;
dp
->
tx2
=
0
;
}
/* Start next packet if one is ready */
dp
->
tx_started
=
false
;
if
(
dp
->
tx1
)
{
dp83902a_start_xmit
(
dp
->
tx1
,
dp
->
tx1_len
);
dp
->
tx_int
=
1
;
}
else
if
(
dp
->
tx2
)
{
dp83902a_start_xmit
(
dp
->
tx2
,
dp
->
tx2_len
);
dp
->
tx_int
=
2
;
}
else
{
dp
->
tx_int
=
0
;
}
/* Tell higher level we sent this packet */
uboot_push_tx_done
(
key
,
0
);
}
/*
* Read the tally counters to clear them. Called in response to a CNT
* interrupt.
*/
static
void
dp83902a_ClearCounters
(
void
)
{
struct
dp83902a_priv_data
*
dp
=
(
struct
dp83902a_priv_data
*
)
&
nic
;
u8
*
base
=
dp
->
base
;
u8
cnt1
,
cnt2
,
cnt3
;
DP_IN
(
base
,
DP_FER
,
cnt1
);
DP_IN
(
base
,
DP_CER
,
cnt2
);
DP_IN
(
base
,
DP_MISSED
,
cnt3
);
DP_OUT
(
base
,
DP_ISR
,
DP_ISR_CNT
);
}
/*
* Deal with an overflow condition. This code follows the procedure set
* out in section 7.0 of the datasheet.
*/
static
void
dp83902a_Overflow
(
void
)
{
struct
dp83902a_priv_data
*
dp
=
(
struct
dp83902a_priv_data
*
)
&
nic
;
u8
*
base
=
dp
->
base
;
u8
isr
;
/* Issue a stop command and wait 1.6ms for it to complete. */
DP_OUT
(
base
,
DP_CR
,
DP_CR_STOP
|
DP_CR_NODMA
);
CYGACC_CALL_IF_DELAY_US
(
1600
);
/* Clear the remote byte counter registers. */
DP_OUT
(
base
,
DP_RBCL
,
0
);
DP_OUT
(
base
,
DP_RBCH
,
0
);
/* Enter loopback mode while we clear the buffer. */
DP_OUT
(
base
,
DP_TCR
,
DP_TCR_LOCAL
);
DP_OUT
(
base
,
DP_CR
,
DP_CR_START
|
DP_CR_NODMA
);
/*
* Read in as many packets as we can and acknowledge any and receive
* interrupts. Since the buffer has overflowed, a receive event of
* some kind will have occured.
*/
dp83902a_RxEvent
();
DP_OUT
(
base
,
DP_ISR
,
DP_ISR_RxP
|
DP_ISR_RxE
);
/* Clear the overflow condition and leave loopback mode. */
DP_OUT
(
base
,
DP_ISR
,
DP_ISR_OFLW
);
DP_OUT
(
base
,
DP_TCR
,
DP_TCR_NORMAL
);
/*
* If a transmit command was issued, but no transmit event has occured,
* restart it here.
*/
DP_IN
(
base
,
DP_ISR
,
isr
);
if
(
dp
->
tx_started
&&
!
(
isr
&
(
DP_ISR_TxP
|
DP_ISR_TxE
)))
{
DP_OUT
(
base
,
DP_CR
,
DP_CR_NODMA
|
DP_CR_TXPKT
|
DP_CR_START
);
}
}
static
void
dp83902a_poll
(
void
)
{
struct
dp83902a_priv_data
*
dp
=
(
struct
dp83902a_priv_data
*
)
&
nic
;
u8
*
base
=
dp
->
base
;
u8
isr
;
DP_OUT
(
base
,
DP_CR
,
DP_CR_NODMA
|
DP_CR_PAGE0
|
DP_CR_START
);
DP_IN
(
base
,
DP_ISR
,
isr
);
while
(
0
!=
isr
)
{
/*
* The CNT interrupt triggers when the MSB of one of the error
* counters is set. We don't much care about these counters, but
* we should read their values to reset them.
*/
if
(
isr
&
DP_ISR_CNT
)
{
dp83902a_ClearCounters
();
}
/*
* Check for overflow. It's a special case, since there's a
* particular procedure that must be followed to get back into
* a running state.a
*/
if
(
isr
&
DP_ISR_OFLW
)
{
dp83902a_Overflow
();
}
else
{
/*
* Other kinds of interrupts can be acknowledged simply by
* clearing the relevant bits of the ISR. Do that now, then
* handle the interrupts we care about.
*/
DP_OUT
(
base
,
DP_ISR
,
isr
);
/* Clear set bits */
if
(
!
dp
->
running
)
break
;
/* Is this necessary? */
/*
* Check for tx_started on TX event since these may happen
* spuriously it seems.
*/
if
(
isr
&
(
DP_ISR_TxP
|
DP_ISR_TxE
)
&&
dp
->
tx_started
)
{
dp83902a_TxEvent
();
}
if
(
isr
&
(
DP_ISR_RxP
|
DP_ISR_RxE
))
{
dp83902a_RxEvent
();
}
}
DP_IN
(
base
,
DP_ISR
,
isr
);
}
}
/* U-boot specific routines */
static
u8
*
pbuf
=
NULL
;
static
int
pkey
=
-
1
;
static
int
initialized
=
0
;
void
uboot_push_packet_len
(
int
len
)
{
PRINTK
(
"pushed len = %d
\n
"
,
len
);
if
(
len
>=
2000
)
{
printf
(
"NE2000: packet too big
\n
"
);
return
;
}
dp83902a_recv
(
&
pbuf
[
0
],
len
);
/*Just pass it to the upper layer*/
NetReceive
(
&
pbuf
[
0
],
len
);
}
void
uboot_push_tx_done
(
int
key
,
int
val
)
{
PRINTK
(
"pushed key = %d
\n
"
,
key
);
pkey
=
key
;
}
int
eth_init
(
bd_t
*
bd
)
{
int
r
;
u8
dev_addr
[
6
];
char
ethaddr
[
20
];
PRINTK
(
"### eth_init
\n
"
);
if
(
!
pbuf
)
{
pbuf
=
malloc
(
2000
);
if
(
!
pbuf
)
{
printf
(
"Cannot allocate rx buffer
\n
"
);
return
-
1
;
}
}
#ifdef CONFIG_DRIVER_NE2000_CCR
{
vu_char
*
p
=
(
vu_char
*
)
CONFIG_DRIVER_NE2000_CCR
;
PRINTK
(
"CCR before is %x
\n
"
,
*
p
);
*
p
=
CONFIG_DRIVER_NE2000_VAL
;
PRINTK
(
"CCR after is %x
\n
"
,
*
p
);
}
#endif
nic
.
base
=
(
u8
*
)
CONFIG_DRIVER_NE2000_BASE
;
r
=
get_prom
(
dev_addr
,
nic
.
base
);
if
(
!
r
)
return
-
1
;
sprintf
(
ethaddr
,
"%02X:%02X:%02X:%02X:%02X:%02X"
,
dev_addr
[
0
],
dev_addr
[
1
],
dev_addr
[
2
],
dev_addr
[
3
],
dev_addr
[
4
],
dev_addr
[
5
])
;
PRINTK
(
"Set environment from HW MAC addr =
\"
%s
\"\n
"
,
ethaddr
);
setenv
(
"ethaddr"
,
ethaddr
);
nic
.
data
=
nic
.
base
+
DP_DATA
;
nic
.
tx_buf1
=
START_PG
;
nic
.
tx_buf2
=
START_PG2
;
nic
.
rx_buf_start
=
RX_START
;
nic
.
rx_buf_end
=
RX_END
;
if
(
dp83902a_init
()
==
false
)
return
-
1
;
dp83902a_start
(
dev_addr
);
initialized
=
1
;
return
0
;
}
void
eth_halt
()
{
PRINTK
(
"### eth_halt
\n
"
);
if
(
initialized
)
dp83902a_stop
();
initialized
=
0
;
}
int
eth_rx
()
{
dp83902a_poll
();
return
1
;
}
int
eth_send
(
volatile
void
*
packet
,
int
length
)
{
int
tmo
;
PRINTK
(
"### eth_send
\n
"
);
pkey
=
-
1
;
dp83902a_send
((
u8
*
)
packet
,
length
,
666
);
tmo
=
get_timer
(
0
)
+
TOUT
*
CFG_HZ
;
while
(
1
)
{
dp83902a_poll
();
if
(
pkey
!=
-
1
)
{
PRINTK
(
"Packet sucesfully sent
\n
"
);
return
0
;
}
if
(
get_timer
(
0
)
>=
tmo
)
{
printf
(
"transmission error (timoeut)
\n
"
);
return
0
;
}
}
return
0
;
}
drivers/net/ne2000_base.h
浏览文件 @
65d4a75f
...
...
@@ -80,10 +80,35 @@ are GPL, so this is, of course, GPL.
#define __NE2000_BASE_H__
#define bool int
#define false 0
#define true 1
/*
* Debugging details
*
* Set to perms of:
* 0 disables all debug output
* 1 for process debug output
* 2 for added data IO output: get_reg, put_reg
* 4 for packet allocation/free output
* 8 for only startup status, so we can tell we're installed OK
*/
#if 0
#define DEBUG 0xf
#else
#define DEBUG 0
#endif
#if DEBUG & 1
#define DEBUG_FUNCTION() do { printf("%s\n", __FUNCTION__); } while (0)
#define DEBUG_LINE() do { printf("%d\n", __LINE__); } while (0)
#define PRINTK(args...) printf(args)
#else
#define DEBUG_FUNCTION() do {} while(0)
#define DEBUG_LINE() do {} while(0)
#define PRINTK(args...)
#endif
/* timeout for tx/rx in s */
#define TOUT 5
/* Ether MAC address size */
...
...
@@ -119,11 +144,6 @@ typedef struct dp83902a_priv_data {
int
rx_buf_start
,
rx_buf_end
;
}
dp83902a_priv_data_t
;
/*
* Some forward declarations
*/
static
void
dp83902a_poll
(
void
);
/* ------------------------------------------------------------------------ */
/* Register offsets */
...
...
@@ -281,4 +301,8 @@ static void dp83902a_poll(void);
#define IEEE_8023_MAX_FRAME 1518
/* Largest possible ethernet frame */
#define IEEE_8023_MIN_FRAME 64
/* Smallest possible ethernet frame */
/* Functions */
int
get_prom
(
u8
*
mac_addr
,
u8
*
base_addr
);
#endif
/* __NE2000_BASE_H__ */
drivers/net/tsec.c
浏览文件 @
65d4a75f
...
...
@@ -1366,6 +1366,8 @@ struct phy_info phy_info_VSC8601 = {
{
MIIM_EXT_PAGE_ACCESS
,
0
,
NULL
},
#endif
#endif
{
MIIM_ANAR
,
MIIM_ANAR_INIT
,
NULL
},
{
MIIM_CONTROL
,
MIIM_CONTROL_RESTART
,
&
mii_cr_init
},
{
miim_end
,}
},
(
struct
phy_cmd
[]){
/* startup */
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录