1481 lines
42 KiB
C
1481 lines
42 KiB
C
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
|
|
/*
|
|
* drivers/net/aml_ethernet.c
|
|
*
|
|
* Copyright (C) 2020 Amlogic, Inc. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
#include <linux/types.h>
|
|
#include <config.h>
|
|
#include <malloc.h>
|
|
#include <common.h>
|
|
#include <net.h>
|
|
#include <asm/u-boot.h>
|
|
#include <asm/cache.h>
|
|
|
|
/**
|
|
* Amlogic mason headers
|
|
*
|
|
* arch/arm/include/asm/arch-m*
|
|
*/
|
|
#include <asm/arch/io.h>
|
|
#include "aml_eth_reg.h"
|
|
#include "aml_phy_8700.h"
|
|
#include <asm/arch/secure_apb.h>
|
|
|
|
|
|
|
|
#define aml_eth_readl(x) (readl((x)&0xffffffffL)&0xffffffffL)
|
|
#define aml_eth_writel(val,addr) (writel(((val)&0xffffffffL),((addr)&0xffffffffL)))
|
|
#define AML_READ_CBUS_REG(reg)
|
|
/**
|
|
* arch/arm/cpu/aml_meson
|
|
*
|
|
*/
|
|
|
|
#define NET_DMA_BUFFER_SIZE 0x20000
|
|
|
|
static unsigned char g_bi_enetaddr[6] = {0, 0, 0, 0, 0, 0};
|
|
static struct _gStruct* gS = NULL;
|
|
static struct _rx_desc* g_rx = NULL;
|
|
static struct _tx_desc* g_tx = NULL;
|
|
static struct _rx_desc* g_current_rx = NULL;
|
|
static struct _tx_desc* g_current_tx = NULL;
|
|
static int g_nInitialized = 0 ;
|
|
static unsigned int g_phy_Identifier = 0;
|
|
static unsigned int g_speed_enforce=0;
|
|
static unsigned int g_mdc_clock_range=ETH_MAC_4_GMII_Addr_CR_100_150;
|
|
#define PHY_SMSC_8700 0x7c0c4
|
|
#define PHY_SMSC_8720 0x7c0f1
|
|
#define PHY_ATHEROS_8032 0x004dd023
|
|
#define PHY_ATHEROS_8035 0x004dd072
|
|
#define PHY_IC_IP101ALF 0x02430c54
|
|
#define PHY_MICREL_8091 0x221560
|
|
#define PHY_INTERNAL 0x79898963
|
|
#define PHY_RTL_8211F 0x001cc916
|
|
#define PHY_MICREL_KSZ9031 0x00221620
|
|
#define PHY_MICREL_KSZ9031RNX 0x00221622
|
|
#define MAC_MODE_RMII_CLK_EXTERNAL 0
|
|
#define MAC_MODE_RMII_CLK_INTERNAL 1
|
|
#define MAC_MODE_RGMII 2
|
|
static int g_mac_mode = MAC_MODE_RGMII;
|
|
|
|
static int g_debug = 0;
|
|
//#define ET_DEBUG
|
|
/*
|
|
M6TV
|
|
23
|
|
M6TVlite
|
|
24
|
|
M8
|
|
25
|
|
M6TVd
|
|
26
|
|
M8baby
|
|
27
|
|
G9TV
|
|
28
|
|
*/
|
|
static unsigned int get_cpuid(void){
|
|
return READ_CBUS_REG(0x1f53)&0xff;
|
|
}
|
|
#ifdef INTERNAL_PHY
|
|
#define SMI_ADDR_TSTCNTL 20
|
|
#define SMI_ADDR_TSTREAD1 21
|
|
#define SMI_ADDR_TSTREAD2 22
|
|
#define SMI_ADDR_TSTWRITE 23
|
|
|
|
#define WR_ADDR_A0CFG 0x11
|
|
#define WR_ADDR_A1CFG 0x12
|
|
#define WR_ADDR_A2CFG 0x13
|
|
#define WR_ADDR_A3CFG 0x14
|
|
#define WR_ADDR_A4CFG 0x15
|
|
#define WR_ADDR_A5CFG 0x16
|
|
#define WR_ADDR_A6CFG 0x17
|
|
#define WR_ADDR_A7CFG 0x18
|
|
#define WR_ADDR_A8CFG 0x1a
|
|
#define WR_ADDR_A9CFG 0x1b
|
|
#define WR_ADDR_A10CFG 0x1c
|
|
#define WR_ADDR_A11CFG 0x1d
|
|
|
|
#define RD_ADDR_A3CFG (0x14 << 5)
|
|
#define RD_ADDR_A4CFG (0x15 << 5)
|
|
#define RD_ADDR_A5CFG (0x16 << 5)
|
|
#define RD_ADDR_A6CFG (0x17 << 5)
|
|
|
|
#define TSTCNTL_RD ((1 << 15) | (1 << 10))
|
|
#define TSTCNTL_WR ((1 << 14) | (1 << 10))
|
|
#endif
|
|
|
|
/*
|
|
|
|
*/
|
|
|
|
static void hardware_reset(void)
|
|
{
|
|
/* PHY hardware reset */
|
|
/*
|
|
if (get_cpuid() == 0x16) {
|
|
CLEAR_CBUS_REG_MASK(PREG_PAD_GPIO5_O, 1 << 15);
|
|
udelay(500000);
|
|
SET_CBUS_REG_MASK(PREG_PAD_GPIO5_O, 1 << 15);
|
|
}
|
|
if (get_cpuid() == 0x19) {
|
|
CLEAR_CBUS_REG_MASK(PREG_PAD_GPIO1_O, 1 << 31);
|
|
udelay(500000);
|
|
SET_CBUS_REG_MASK(PREG_PAD_GPIO1_O, 1 << 31);
|
|
}
|
|
if (get_cpuid() == 0x1b) { // m8b It is not known when the chips to change //27
|
|
CLEAR_CBUS_REG_MASK(PREG_PAD_GPIO3_O, 1 << 23);
|
|
udelay(500000);
|
|
SET_CBUS_REG_MASK(PREG_PAD_GPIO3_O, 1 << 23);
|
|
}*/
|
|
if (get_cpuid() == 0x1f) { // s905
|
|
clrbits_le32(PREG_PAD_GPIO3_O, 1 << 14);
|
|
udelay(500000);
|
|
setbits_le32(PREG_PAD_GPIO3_O, 1 << 14);
|
|
}
|
|
printf("ETH PHY hardware reset OK\n");
|
|
|
|
return;
|
|
}
|
|
static void phy_reg_wr(int phyad, unsigned int reg, unsigned int val)
|
|
{
|
|
unsigned long busy = 0, tmp = 0;
|
|
unsigned int phyaddr;
|
|
unsigned int phyreg;
|
|
unsigned long reg4;
|
|
|
|
phyaddr = phyad << ETH_MAC_4_GMII_Addr_PA_P;
|
|
phyreg = reg << ETH_MAC_4_GMII_Addr_GR_P;
|
|
|
|
reg4 = phyaddr | phyreg | g_mdc_clock_range | ETH_MAC_4_GMII_Addr_GW | ETH_MAC_4_GMII_Addr_GB;
|
|
aml_eth_writel(val, ETH_MAC_5_GMII_Data);
|
|
aml_eth_writel(reg4, ETH_MAC_4_GMII_Addr);
|
|
busy = 1;
|
|
while (busy) {
|
|
tmp = aml_eth_readl(ETH_MAC_4_GMII_Addr);
|
|
busy = tmp & 1;
|
|
}
|
|
}
|
|
|
|
static unsigned int phy_reg_rd(int phyad, unsigned int reg)
|
|
{
|
|
unsigned long busy = 0, tmp = 0;
|
|
unsigned int phyaddr;
|
|
unsigned int phyreg;
|
|
unsigned long reg4;
|
|
|
|
phyaddr = phyad << ETH_MAC_4_GMII_Addr_PA_P;
|
|
phyreg = reg << ETH_MAC_4_GMII_Addr_GR_P;
|
|
reg4 = phyaddr | phyreg | g_mdc_clock_range | ETH_MAC_4_GMII_Addr_GB;
|
|
aml_eth_writel(reg4, ETH_MAC_4_GMII_Addr);
|
|
|
|
busy = 1;
|
|
while (busy) {
|
|
tmp = aml_eth_readl(ETH_MAC_4_GMII_Addr);
|
|
busy = tmp & 1;
|
|
}
|
|
|
|
tmp = aml_eth_readl(ETH_MAC_5_GMII_Data);
|
|
|
|
return tmp;
|
|
}
|
|
#ifdef INTERNAL_PHY
|
|
static void initTSTMODE(int phyad)
|
|
{
|
|
phy_reg_wr(phyad, SMI_ADDR_TSTCNTL, 0x0400);
|
|
phy_reg_wr(phyad, SMI_ADDR_TSTCNTL, 0x0000);
|
|
phy_reg_wr(phyad, SMI_ADDR_TSTCNTL, 0x0400);
|
|
|
|
}
|
|
|
|
static void closeTSTMODE(int phyad)
|
|
{
|
|
phy_reg_wr(phyad, SMI_ADDR_TSTCNTL, 0x0000);
|
|
|
|
}
|
|
|
|
|
|
static void init_internal_phy(int phyad)
|
|
{
|
|
initTSTMODE(phyad);
|
|
// write tstcntl addr val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x1354);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR);//write addr 0
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x38);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A0CFG);//write addr 0x11
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x0c00);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A1CFG);//write addr 0x12
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x3e00);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A2CFG);//write addr 0x13
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0xf902);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A3CFG);//write addr 0x14
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x3412);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A4CFG);//write addr 0x15
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x2636);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A5CFG);//write addr 0x16
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,3);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A7CFG);//write addr 0x18
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x108);
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A9CFG);//write addr 0x1b
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0xda00);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A11CFG);//write addr 0x1d
|
|
closeTSTMODE(phyad);
|
|
}
|
|
|
|
|
|
void init_internal_phy_10B(int phyad)
|
|
{
|
|
|
|
initTSTMODE(phyad);
|
|
// write tstcntl addr val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x0000);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR);//write addr 0
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x38);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A0CFG);//write addr 0x11
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x0c00);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A1CFG);//write addr 0x12
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x3e00);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A2CFG);//write addr 0x13
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0xf902);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A3CFG);//write addr 0x14
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x3412);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A4CFG);//write addr 0x15
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x2236);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A5CFG);//write addr 0x16
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,3);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A7CFG);//write addr 0x18
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x108);//write val by channel (2)
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A9CFG);//write addr 0x1b
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0xda00);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A11CFG);//write addr 0x1d
|
|
closeTSTMODE(phyad);
|
|
}
|
|
|
|
void init_internal_phy_100B(int phyad)
|
|
{
|
|
|
|
initTSTMODE(phyad);
|
|
// write tstcntl addr val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x9354);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|0x00);//write addr 0x00
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x38);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A0CFG);//write addr 0x11
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x0c00);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A1CFG);//write addr 0x12
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x3e00);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A2CFG);//write addr 0x13
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0xf902);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A3CFG);//write addr 0x14
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x3412);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A4CFG);//write addr 0x15
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0xa406);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A5CFG);//write addr 0x16
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x0003);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A7CFG);//write addr 0x18
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0x00a6);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A9CFG);//write addr 0x1b
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTWRITE,0xda00);//write val
|
|
phy_reg_wr(phyad,SMI_ADDR_TSTCNTL,TSTCNTL_WR|WR_ADDR_A11CFG);//write addr 0x1d
|
|
closeTSTMODE(phyad);
|
|
}
|
|
#endif
|
|
static inline void _dcache_flush_range_for_net(unsigned long startAddr, unsigned long endAddr)
|
|
{
|
|
flush_dcache_range(startAddr, ROUND(endAddr, ETH_CACHE_LINE_SIZE));
|
|
}
|
|
|
|
static inline void _dcache_inv_range_for_net(unsigned long startAddr, unsigned long endAddr)
|
|
{
|
|
|
|
invalidate_dcache_range(startAddr, ROUND(endAddr, ETH_CACHE_LINE_SIZE));
|
|
}
|
|
|
|
static unsigned int detect_phyad(void)
|
|
{
|
|
unsigned int testval = 0;
|
|
int i;
|
|
static int s_phyad = -1;
|
|
|
|
if (s_phyad != -1) {
|
|
return s_phyad;
|
|
}
|
|
for (i = 0; i < 32; i++) {
|
|
testval = phy_reg_rd(i, PHY_SR); //read the SR register..
|
|
if (testval != 0x0000 && testval != 0xffff) {
|
|
s_phyad = i;
|
|
return s_phyad;
|
|
}
|
|
}
|
|
return 0xffff;
|
|
}
|
|
|
|
static void set_mac_mode(void)
|
|
{
|
|
printf("set_mac_mode(%d)\n", g_mac_mode);
|
|
if (g_mac_mode == 2) {
|
|
/* RGMII */
|
|
aml_eth_writel(aml_eth_readl(ETH_MAC_0_Configuration)|(ETH_MAC_0_Configuration_PS_GMII | ETH_MAC_0_Configuration_TC | ETH_MAC_0_Configuration_DM
|
|
| ETH_MAC_0_Configuration_RE | ETH_MAC_0_Configuration_TE), ETH_MAC_0_Configuration);
|
|
} else {
|
|
/* RMII */
|
|
aml_eth_writel(aml_eth_readl(ETH_MAC_0_Configuration)|(ETH_MAC_0_Configuration_PS_MII | ETH_MAC_0_Configuration_FES_100M | ETH_MAC_0_Configuration_DM
|
|
| ETH_MAC_0_Configuration_RE | ETH_MAC_0_Configuration_TE), ETH_MAC_0_Configuration);
|
|
}
|
|
|
|
aml_eth_writel((ETH_MAC_1_Frame_Filter_PM | ETH_MAC_1_Frame_Filter_RA), ETH_MAC_1_Frame_Filter);
|
|
}
|
|
|
|
static void set_mac_addrs(void *ptr)
|
|
{
|
|
unsigned int mac_filter = 0;
|
|
unsigned char * p = (unsigned char *)ptr;
|
|
|
|
mac_filter = (p[5] << 8) | p[4];
|
|
aml_eth_writel(mac_filter, ETH_MAC_Addr0_High);
|
|
mac_filter = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
|
|
aml_eth_writel(mac_filter, ETH_MAC_Addr0_Low);
|
|
}
|
|
|
|
static void netdev_chk(void)
|
|
{
|
|
unsigned int rint, rint2;
|
|
static unsigned int old_rint = -1;
|
|
unsigned int id;
|
|
int speed, full;
|
|
|
|
speed = full = 0;
|
|
id = detect_phyad();
|
|
rint2 = 3000;
|
|
if (g_speed_enforce)
|
|
{
|
|
//printf("use enforce net speed\n");
|
|
rint=phy_reg_rd(id,PHY_SR);
|
|
|
|
}else{
|
|
do {
|
|
rint = phy_reg_rd(id, PHY_SR);
|
|
if ((rint & PHY_SR_ANCOMPLETE)) {
|
|
break;
|
|
}
|
|
udelay(1000);
|
|
} while (rint2-- > 0);
|
|
if (!(rint & PHY_SR_ANCOMPLETE)) {
|
|
printf("phy auto link failed\n");
|
|
}
|
|
}
|
|
if (old_rint != rint) {
|
|
if (g_debug > 1)
|
|
printf("netdev_chk() g_phy_Identifier: 0x%x\n", g_phy_Identifier);
|
|
switch (g_phy_Identifier) {
|
|
case PHY_ATHEROS_8032:
|
|
rint2 = phy_reg_rd(id, 17);
|
|
speed = (rint2 & (1 << 14)) >> 14;
|
|
full = ((rint2) & (1 << 13));
|
|
gS->linked = rint2 & (1 << 10);
|
|
break;
|
|
case PHY_ATHEROS_8035:
|
|
rint2 = phy_reg_rd(id, 17);
|
|
speed = (rint2 & (3 << 14)) >> 14;
|
|
full = ((rint2) & (1 << 13));
|
|
gS->linked = rint2 & (1 << 10);
|
|
break;
|
|
case PHY_RTL_8211F:
|
|
rint2 = phy_reg_rd(id, 26);
|
|
speed = (rint2 & (3 << 4)) >> 4;
|
|
full = ((rint2) & (1 << 3));
|
|
rint2 = phy_reg_rd(id,1);
|
|
gS->linked = rint2&(1<<2);
|
|
break;
|
|
case PHY_MICREL_KSZ9031:
|
|
case PHY_MICREL_KSZ9031RNX:
|
|
rint2 = phy_reg_rd(id, 31);
|
|
speed = (rint2 & (1 << 4))? 0:((rint2 &(1<<5))? 1:2);
|
|
full = ((rint2) & (1 << 3));
|
|
rint2 = phy_reg_rd(id,1);
|
|
gS->linked = rint2&(1<<2);
|
|
break;
|
|
case PHY_IC_IP101ALF:
|
|
rint2 = phy_reg_rd(id,1);
|
|
gS->linked = rint2&(1<<2);
|
|
rint2 = phy_reg_rd(id,0);
|
|
speed = (rint2 & (0x1<<8))? 1:0;
|
|
rint2 = phy_reg_rd(id,5);
|
|
full = (rint2 & (0x1<<7))? 1:0;
|
|
break;
|
|
case PHY_MICREL_8091:
|
|
rint2 = phy_reg_rd(id,1);
|
|
gS->linked = rint2&(1<<2);
|
|
rint2 = phy_reg_rd(id,30);
|
|
speed = (rint2 & (0x1<<1))? 1:0;
|
|
rint2 = phy_reg_rd(id,5);
|
|
full = (rint2 & 0x1)? 1:0;
|
|
break;
|
|
case PHY_INTERNAL:
|
|
rint2 = phy_reg_rd(id, 31);
|
|
speed = (rint2 & (1 << 3)) >> 3;
|
|
full = ((rint2 >> 4) & 1);
|
|
gS->linked = rint2 & (1 << 2);
|
|
break;
|
|
case PHY_SMSC_8700:
|
|
case PHY_SMSC_8720:
|
|
default:
|
|
rint2 = phy_reg_rd(id, 31);
|
|
speed = (rint2 & (1 << 3)) >> 3;
|
|
full = ((rint2 >> 4) & 1);
|
|
gS->linked = rint2 & (1 << 2);
|
|
break;
|
|
}
|
|
/* phy_auto_negotiation_set */
|
|
if (full) {
|
|
printf("duplex\n");
|
|
aml_eth_writel(aml_eth_readl(ETH_MAC_0_Configuration) | ETH_MAC_0_Configuration_DM, ETH_MAC_0_Configuration);
|
|
} else {
|
|
printf("half duplex\n");
|
|
aml_eth_writel(aml_eth_readl(ETH_MAC_0_Configuration) & ~ ETH_MAC_0_Configuration_DM, ETH_MAC_0_Configuration);
|
|
}
|
|
if (speed == 0) {
|
|
printf("10m\n");
|
|
#ifdef INTERNAL_PHY
|
|
init_internal_phy_10B(id);
|
|
int val =0x4100b040;
|
|
aml_eth_writel(val,ETH_PLL_CNTL);
|
|
#endif
|
|
aml_eth_writel(aml_eth_readl(ETH_MAC_0_Configuration) & ~ ETH_MAC_0_Configuration_FES_100M, ETH_MAC_0_Configuration);
|
|
aml_eth_writel(((aml_eth_readl(ETH_MAC_0_Configuration)) | (ETH_MAC_0_Configuration_PS_MII)), ETH_MAC_0_Configuration); // program mac
|
|
#ifndef NEW_MAC_LOGIC
|
|
if ( get_cpuid() < 0x1B ) {
|
|
aml_eth_writel(aml_eth_readl(ETH_PLL_CNTL) & ~ETH_PLL_CNTL_DIVEN, ETH_PLL_CNTL); // Disable the Ethernet clocks
|
|
// ---------------------------------------------
|
|
// Test 50Mhz Input Divide by 2
|
|
// ---------------------------------------------
|
|
// Select divide by 20
|
|
aml_eth_writel(aml_eth_readl(ETH_PLL_CNTL) & ~ETH_PLL_CNTL_DESEND, ETH_PLL_CNTL); // desc endianess "same order"
|
|
aml_eth_writel(aml_eth_readl(ETH_PLL_CNTL) & ~ETH_PLL_CNTL_DATEND, ETH_PLL_CNTL); // data endianess "little"
|
|
aml_eth_writel(aml_eth_readl(ETH_PLL_CNTL) & ~ETH_PLL_CNTL_MACSPD, ETH_PLL_CNTL); // divide by 20
|
|
aml_eth_writel(aml_eth_readl(ETH_PLL_CNTL) | ETH_PLL_CNTL_DIVEN, ETH_PLL_CNTL); // enable Ethernet clocks
|
|
}
|
|
#endif
|
|
} else if (speed == 1) {
|
|
printf("100m\n");
|
|
#ifdef INTERNAL_PHY
|
|
init_internal_phy_100B(id);
|
|
int val = (8<<27)|(7 << 24)|(1<<16)|(1<<15)|(1 << 13)|(1 << 12)|(4 << 4)|(0 << 1);
|
|
aml_eth_writel(val,ETH_PLL_CNTL);
|
|
#endif
|
|
aml_eth_writel(aml_eth_readl(ETH_MAC_0_Configuration) | ETH_MAC_0_Configuration_FES_100M, ETH_MAC_0_Configuration); // program mac
|
|
aml_eth_writel(((aml_eth_readl(ETH_MAC_0_Configuration)) | (ETH_MAC_0_Configuration_PS_MII)), ETH_MAC_0_Configuration); // program mac
|
|
#ifndef NEW_MAC_LOGIC
|
|
|
|
if (get_cpuid()< 0x1B) {
|
|
aml_eth_writel(aml_eth_readl(ETH_PLL_CNTL) & ~ETH_PLL_CNTL_DIVEN, ETH_PLL_CNTL); // Disable the Ethernet clocks
|
|
// ---------------------------------------------
|
|
// Test 50Mhz Input Divide by 2
|
|
// ---------------------------------------------
|
|
// Select divide by 2
|
|
aml_eth_writel(aml_eth_readl(ETH_PLL_CNTL) & ~ETH_PLL_CNTL_DESEND, ETH_PLL_CNTL); // desc endianess "same order"
|
|
aml_eth_writel(aml_eth_readl(ETH_PLL_CNTL) & ~ETH_PLL_CNTL_DATEND, ETH_PLL_CNTL); // data endianess "little"
|
|
aml_eth_writel(aml_eth_readl(ETH_PLL_CNTL) | ETH_PLL_CNTL_MACSPD, ETH_PLL_CNTL); // divide by 2
|
|
aml_eth_writel(aml_eth_readl(ETH_PLL_CNTL) | ETH_PLL_CNTL_DIVEN, ETH_PLL_CNTL); // enable Ethernet clocks
|
|
}
|
|
#endif
|
|
} else {
|
|
printf("1000m\n");
|
|
#if defined(NEW_MAC_LOGIC)
|
|
aml_eth_writel(((aml_eth_readl(ETH_MAC_0_Configuration)) & (~ETH_MAC_0_Configuration_PS_MII)) | (1<<13), ETH_MAC_0_Configuration); // program mac
|
|
aml_eth_writel(aml_eth_readl(ETH_MAC_0_Configuration) & (~ETH_MAC_0_Configuration_FES_100M), ETH_MAC_0_Configuration); // program mac
|
|
|
|
#else
|
|
if (get_cpuid() >= 0x1B) {
|
|
aml_eth_writel(((aml_eth_readl(ETH_MAC_0_Configuration)) & (~ETH_MAC_0_Configuration_PS_MII)) | (1<<13), ETH_MAC_0_Configuration); // program mac
|
|
aml_eth_writel(aml_eth_readl(ETH_MAC_0_Configuration) & (~ETH_MAC_0_Configuration_FES_100M), ETH_MAC_0_Configuration); // program mac
|
|
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* link_changed */
|
|
#if defined(ET_DEBUG)
|
|
unsigned int regs = 0, val;
|
|
for (regs = 0; regs <= 31; regs++) {
|
|
val = phy_reg_rd(id, regs);
|
|
printf("reg[%d]=%x\n", regs, (unsigned)val);
|
|
}
|
|
#endif
|
|
old_rint = rint;
|
|
}
|
|
}
|
|
|
|
static void set_phy_mode(void)
|
|
{
|
|
unsigned int phyad = -1;
|
|
unsigned int val;
|
|
|
|
phyad = 1;
|
|
if (phyad > 32 || phyad < 0) {
|
|
return;
|
|
}
|
|
|
|
if (g_debug > 1)
|
|
printf("set_phy_mode() g_phy_Identifier: 0x%x\n", g_phy_Identifier);
|
|
switch (g_phy_Identifier) {
|
|
case PHY_ATHEROS_8032:
|
|
case PHY_ATHEROS_8035:
|
|
case PHY_RTL_8211F:
|
|
break;
|
|
case PHY_MICREL_8091:
|
|
val = phy_reg_rd(phyad, 0x16);
|
|
phy_reg_wr(phyad, 0x16, (val & ~(0x8020)));
|
|
break;
|
|
case PHY_INTERNAL:
|
|
break;
|
|
case PHY_SMSC_8700:
|
|
case PHY_SMSC_8720:
|
|
val = PHY_SPMD_MIIMODE_RMII | (PHY_MODE_BUS_ALL_AE << PHY_SPMD_MODE_P) | (phyad << PHY_SPMD_PHYAD_P);
|
|
phy_reg_wr(phyad, PHY_SPMD, val);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Reset and idle the chip, putting all registers into
|
|
* a reasonable state */
|
|
static int eth_reset(struct _gStruct* emac_config)
|
|
{
|
|
int i, k, phyad;
|
|
unsigned int val,ori_ctl_val=0;
|
|
struct _gStruct* m=emac_config;
|
|
if (get_cpuid() >= 0x16) {
|
|
/* make sure PHY power-on */
|
|
set_phy_mode();
|
|
}
|
|
#define NET_MAX_RESET_TEST 1000
|
|
if (g_speed_enforce) ori_ctl_val=phy_reg_rd(1, PHY_CR) ;
|
|
for (i = 0; i < NET_MAX_RESET_TEST; i++) {
|
|
/* Software Reset MAC */
|
|
aml_eth_writel(ETH_DMA_0_Bus_Mode_SWR, ETH_DMA_0_Bus_Mode);
|
|
for (k = 0; k < NET_MAX_RESET_TEST; k++) {
|
|
udelay(100);
|
|
|
|
if (!(aml_eth_readl(ETH_DMA_0_Bus_Mode)Ð_DMA_0_Bus_Mode_SWR)) {
|
|
break;
|
|
}
|
|
}
|
|
if (k >= NET_MAX_RESET_TEST) {
|
|
printf("Error: Fail to reset mac!(%d)\n", k);
|
|
return -1;
|
|
} else {
|
|
printf("Success: reset mac OK!(%d)\n", k);
|
|
}
|
|
|
|
udelay(100000);
|
|
hardware_reset();
|
|
udelay(100000);
|
|
phyad = detect_phyad();
|
|
if (phyad > 32 || phyad < 0) {
|
|
continue;
|
|
}
|
|
/* set phy work mode */
|
|
/*
|
|
val = PHY_SPMD_MIIMODE_RMII | (PHY_MODE_BUS_ALL_AE << PHY_SPMD_MODE_P) | (phyad << PHY_SPMD_PHYAD_P);
|
|
phy_reg_wr(phyad, PHY_SPMD, val);
|
|
*/
|
|
/* get phy_Identifier */
|
|
val = phy_reg_rd(phyad, 2);
|
|
g_phy_Identifier = val << 16;
|
|
val = phy_reg_rd(phyad, 3);
|
|
g_phy_Identifier |= val;
|
|
printf("find net phy id=0x%x, phyad=%d\n", (unsigned int)g_phy_Identifier, phyad);
|
|
|
|
if (g_phy_Identifier == PHY_IC_IP101ALF) {
|
|
//if(get_cpuid() == 0x16)
|
|
// WRITE_CBUS_REG(HHI_ETH_CLK_CNTL, 0x120); // phy ip101 need clock phase normal
|
|
#ifndef NEW_MAC_LOGIC
|
|
//if(get_cpuid() == 0x19)
|
|
// WRITE_CBUS_REG(HHI_ETH_CLK_CNTL, 0xf00); // phy ip101 need clock phase normal
|
|
#endif
|
|
}
|
|
/* Software Reset PHY */
|
|
phy_reg_wr(phyad, PHY_CR, PHY_CR_RST);
|
|
for (k = 0; k < NET_MAX_RESET_TEST; k++) {
|
|
udelay(1000);
|
|
val = phy_reg_rd(phyad, PHY_CR);
|
|
if (!(val & PHY_CR_RST)) {
|
|
break;
|
|
}
|
|
}
|
|
if (k >= NET_MAX_RESET_TEST) {
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
if (i >= NET_MAX_RESET_TEST) {
|
|
printf("Error to detected phy\n");
|
|
return -1;
|
|
}
|
|
#ifdef INTERNAL_PHY
|
|
init_internal_phy(phyad);
|
|
#endif
|
|
set_phy_mode();
|
|
val = PHY_CR_AN | PHY_CR_RSTAN;
|
|
phy_reg_wr(phyad, PHY_CR, val);
|
|
if (g_speed_enforce == 1)
|
|
{
|
|
while (!(phy_reg_rd(1,1)&(1<<2))) {}; //wait line status stable
|
|
phy_reg_wr(phyad, PHY_CR, ori_ctl_val);
|
|
while (!(phy_reg_rd(1,1)&(1<<2))) {}; //wait new state stable
|
|
|
|
}
|
|
udelay(10);
|
|
|
|
set_mac_mode();
|
|
|
|
aml_eth_writel((~0), ETH_DMA_5_Status); /* clear all status flag */
|
|
aml_eth_writel(0, ETH_DMA_5_Status);
|
|
aml_eth_writel(0, ETH_DMA_6_Operation_Mode); /* stop RX and TX */
|
|
val = aml_eth_readl(ETH_DMA_8_Missed_Frame_and_Overflow); /* read to clean */
|
|
|
|
aml_eth_writel(0, ETH_DMA_7_Interrupt_Enable); /* disable all interrupt */
|
|
aml_eth_writel((8 << ETH_DMA_0_Bus_Mode_PBL_P) | ETH_DMA_0_Bus_Mode_FB, ETH_DMA_0_Bus_Mode);
|
|
|
|
printf("final_addr[rx-tx]: %p-%p\n", m->rx, m->tx);
|
|
aml_eth_writel((long)m->rx, ETH_DMA_3_Re_Descriptor_List_Addr);
|
|
aml_eth_writel((long)m->tx, ETH_DMA_4_Tr_Descriptor_List_Addr);
|
|
|
|
/* config the interrupt */
|
|
aml_eth_writel(ETH_DMA_7_Interrupt_Enable_TUE | ETH_DMA_7_Interrupt_Enable_TJE
|
|
| ETH_DMA_7_Interrupt_Enable_OVE | ETH_DMA_7_Interrupt_Enable_UNE | ETH_DMA_7_Interrupt_Enable_RIE
|
|
| ETH_DMA_7_Interrupt_Enable_RUE | ETH_DMA_7_Interrupt_Enable_RSE | ETH_DMA_7_Interrupt_Enable_FBE
|
|
| ETH_DMA_7_Interrupt_Enable_AIE | ETH_DMA_7_Interrupt_Enable_NIE, ETH_DMA_7_Interrupt_Enable);
|
|
aml_eth_writel(0, ETH_MAC_Interrupt_Mask);
|
|
|
|
printf("Ethernet reset OK\n");
|
|
return 0;
|
|
}
|
|
|
|
static void DMARXStart(void)
|
|
{
|
|
aml_eth_writel(aml_eth_readl(ETH_DMA_6_Operation_Mode) | ETH_DMA_6_Operation_Mode_SR, ETH_DMA_6_Operation_Mode);
|
|
}
|
|
|
|
static void DMATXStart(void)
|
|
{
|
|
aml_eth_writel(aml_eth_readl(ETH_DMA_6_Operation_Mode) | ETH_DMA_6_Operation_Mode_ST, ETH_DMA_6_Operation_Mode);
|
|
}
|
|
|
|
static void GetDMAStatus(unsigned int* mask, unsigned int* status)
|
|
{
|
|
*mask = aml_eth_readl(ETH_DMA_7_Interrupt_Enable);
|
|
*status = aml_eth_readl(ETH_DMA_5_Status);
|
|
}
|
|
|
|
static void eth_data_dump(unsigned char *p, int len)
|
|
{
|
|
int i, j;
|
|
char s[20];
|
|
|
|
for (i = 0; i < len; i += 16) {
|
|
printf("%p:", p);
|
|
for (j = 0; j < 16 && j < (len - i); j++) {
|
|
s[j] = (p[j] > 15 && p[j] < 128) ? p[j] : '.';
|
|
printf(" %02x", p[j]);
|
|
}
|
|
s[j] = 0;
|
|
printf(" |%s|\n", s);
|
|
p = p + 16;
|
|
}
|
|
}
|
|
|
|
static void eth_tx_dump(unsigned char *p, int len)
|
|
{
|
|
if ((g_debug == 2) || (g_debug == 4)) {
|
|
printf("=====>\n");
|
|
eth_data_dump(p, len);
|
|
}
|
|
}
|
|
|
|
static void eth_rx_dump(unsigned char *p, int len)
|
|
{
|
|
if ((g_debug == 3) || (g_debug == 4)) {
|
|
printf("<=====\n");
|
|
eth_data_dump(p, len);
|
|
}
|
|
}
|
|
|
|
static void aml_eth_halt(struct eth_device * net_current)
|
|
{
|
|
return;
|
|
}
|
|
|
|
static int aml_eth_send(struct eth_device *net_current, void *packet, int length)
|
|
{
|
|
unsigned int mask;
|
|
unsigned int status;
|
|
|
|
if (!g_nInitialized) {
|
|
return -1;
|
|
}
|
|
|
|
eth_tx_dump((unsigned char *)packet, length);
|
|
netdev_chk();
|
|
|
|
struct _tx_desc* pTx = g_current_tx;
|
|
struct _tx_desc* pDma = (struct _tx_desc*)aml_eth_readl(ETH_DMA_18_Curr_Host_Tr_Descriptor);
|
|
|
|
if (pDma != NULL) {
|
|
_dcache_inv_range_for_net((unsigned long)pDma, (unsigned long)(pDma) + sizeof(struct _tx_desc) - 1);
|
|
}
|
|
if (pDma != NULL && !(pDma->tdes0 & TDES0_OWN) && pTx != pDma) {
|
|
//this may not happend,if all the hardware work well...
|
|
//to fixed a bug of the dma maybe lost setting some tx buf to own by host,..;
|
|
//start the current_tx at pDMA
|
|
pTx = pDma;
|
|
}
|
|
if (pDma != pTx) {
|
|
_dcache_inv_range_for_net((unsigned long)pTx, (unsigned long)(pTx + 1) - 1);
|
|
}
|
|
|
|
if (length > ETH_MTU) {
|
|
goto err;
|
|
}
|
|
|
|
if (length < 14) {
|
|
printf("pbuf len error, len=%d\n", length);
|
|
goto err;
|
|
}
|
|
|
|
if (pTx->tdes0 & TDES0_OWN) {
|
|
#if 1
|
|
volatile unsigned long Cdma, Dstatus, status;
|
|
Cdma = aml_eth_readl(ETH_DMA_18_Curr_Host_Tr_Descriptor);
|
|
Dstatus = aml_eth_readl(Cdma);
|
|
status = aml_eth_readl(ETH_DMA_5_Status);
|
|
printf("Current DMA=0x%x, Dstatus=0x%x\n", (unsigned int)Cdma, (unsigned int)Dstatus);
|
|
printf("Current status=0x%x\n", (unsigned int)status);
|
|
printf("no buffer to send\n");
|
|
#endif
|
|
goto err;
|
|
}
|
|
|
|
if (!(unsigned char*)(unsigned long)pTx->tdes2) {
|
|
goto err;
|
|
}
|
|
g_current_tx = (struct _tx_desc*)(unsigned long)pTx->tdes3;
|
|
memcpy((unsigned char*)(unsigned long)pTx->tdes2, (unsigned char*)packet, length);
|
|
//pTx->tdes1 &= DescEndOfRing;
|
|
_dcache_flush_range_for_net((unsigned long)pTx->tdes2, (unsigned long)pTx->tdes2 + length - 1);
|
|
pTx->tdes1 = ((length << TDES1_TBS1_P) & TDES1_TBS1_MASK) | TDES1_FS | TDES1_LS | TDES1_TCH | TDES1_IC;
|
|
pTx->tdes0 = TDES0_OWN;
|
|
_dcache_flush_range_for_net((unsigned long)pTx, (unsigned long)(pTx + 1) - 1);
|
|
|
|
GetDMAStatus(&mask, &status);
|
|
if (status & ETH_DMA_5_Status_TS_SUSP) {
|
|
aml_eth_writel(1, ETH_DMA_1_Tr_Poll_Demand);
|
|
} else {
|
|
DMATXStart();
|
|
}
|
|
|
|
#ifdef ET_DEBUG
|
|
printf("Transfer starting...\n");
|
|
GetDMAStatus(&mask, &status);
|
|
printf("Current status=%x\n", status);
|
|
#endif
|
|
|
|
/* wait for transfer to succeed */
|
|
//unsigned tmo = get_timer (0) + 5 * CONFIG_SYS_HZ; //5S time out
|
|
unsigned tmo = 0;
|
|
do {
|
|
udelay(100);
|
|
GetDMAStatus(&mask, &status);
|
|
if (tmo++ >= 50000) {
|
|
printf("\ntransmission error %#x\n", status);
|
|
break;
|
|
}
|
|
} while (!((status & ETH_DMA_5_Status_NIS) && (status & ETH_DMA_5_Status_TI)));
|
|
|
|
if (status & ETH_DMA_5_Status_NIS) {
|
|
if (status & ETH_DMA_5_Status_TI) {
|
|
aml_eth_writel(ETH_DMA_5_Status_NIS | ETH_DMA_5_Status_TI, ETH_DMA_5_Status);
|
|
}
|
|
if (status & ETH_DMA_5_Status_TU) {
|
|
aml_eth_writel(ETH_DMA_5_Status_NIS | ETH_DMA_5_Status_TU, ETH_DMA_5_Status);
|
|
}
|
|
}
|
|
|
|
#ifdef ET_DEBUG
|
|
//test
|
|
GetDMAStatus(&mask, &status);
|
|
printf("Current status=%x\n", status);
|
|
#endif
|
|
return 0;
|
|
err:
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* each time receive a whole packet
|
|
*/
|
|
static int aml_eth_rx(struct eth_device * net_current)
|
|
{
|
|
unsigned int mask;
|
|
unsigned int status;
|
|
int rxnum = 0;
|
|
int len = 0;
|
|
struct _rx_desc* pRx;
|
|
|
|
if (!g_nInitialized) {
|
|
return -1;
|
|
}
|
|
|
|
netdev_chk();
|
|
|
|
/* Check packet ready or not */
|
|
GetDMAStatus(&mask, &status);
|
|
if (!((status & ETH_DMA_5_Status_NIS) && (status & ETH_DMA_5_Status_RI))) {
|
|
return 0;
|
|
}
|
|
aml_eth_writel(ETH_DMA_5_Status_NIS | ETH_DMA_5_Status_RI, ETH_DMA_5_Status); //clear the int flag
|
|
|
|
if (!g_current_rx) {
|
|
g_current_rx = gS->rx;
|
|
}
|
|
pRx = g_current_rx;
|
|
_dcache_inv_range_for_net((unsigned long)pRx, (unsigned long)(pRx + 1) - 1);
|
|
while (!(pRx->rdes0 & RDES0_OWN)) {
|
|
len = (pRx->rdes0 & RDES0_FL_MASK) >> RDES0_FL_P;
|
|
if (14 >= len) {
|
|
printf("err len=%d\n", len);
|
|
goto NEXT_BUF;
|
|
}
|
|
// pbuf_header(pb, -sizeof(short));
|
|
_dcache_inv_range_for_net((unsigned long)pRx->rdes2, (unsigned long)pRx->rdes2 + len - 1);
|
|
|
|
if (!memcpy((unsigned char*)NetRxPackets[0], (unsigned char*)(unsigned long)pRx->rdes2, len)) {
|
|
printf("memcp error\n");
|
|
goto NEXT_BUF;
|
|
}
|
|
NEXT_BUF:
|
|
pRx->rdes0 = RDES0_OWN;
|
|
_dcache_flush_range_for_net((unsigned long)pRx, (unsigned long)(pRx + 1) - 1);
|
|
pRx = (struct _rx_desc*)(unsigned long)g_current_rx->rdes3;
|
|
_dcache_inv_range_for_net((unsigned long)pRx, (unsigned long)(pRx + 1) - 1);
|
|
g_current_rx = pRx;
|
|
rxnum++;
|
|
NetReceive(NetRxPackets[0], len);
|
|
eth_rx_dump((unsigned char *)NetRxPackets[0], len);
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static int aml_ethernet_init(struct eth_device * net_current, bd_t *bd)
|
|
{
|
|
unsigned long net_dma_start_addr;
|
|
unsigned long net_dma_end_addr;
|
|
unsigned char *net_dma_buffer = NULL;
|
|
unsigned long tx_start, rx_start;
|
|
struct _rx_desc * pRDesc;
|
|
struct _tx_desc * pTDesc;
|
|
unsigned char * bufptr;
|
|
int i;
|
|
if (g_nInitialized) {
|
|
return 0;
|
|
}
|
|
printf("Amlogic Ethernet Init\n");
|
|
|
|
/* alloc the dma buffer */
|
|
net_dma_buffer = memalign(ETH_CACHE_LINE_SIZE, NET_DMA_BUFFER_SIZE);
|
|
net_dma_start_addr = (unsigned long)net_dma_buffer;
|
|
net_dma_end_addr = (unsigned long)(net_dma_buffer + NET_DMA_BUFFER_SIZE);
|
|
|
|
/* init the dma descriptor 128k */
|
|
gS = (struct _gStruct*)malloc(sizeof(struct _gStruct));
|
|
if (net_dma_start_addr != 0 &&
|
|
(net_dma_end_addr - net_dma_start_addr) > (CTX_BUFFER_NUM + CRX_BUFFER_NUM)*CBUFFER_SIZE +
|
|
CRX_BUFFER_NUM * sizeof(struct _rx_desc) + CTX_BUFFER_NUM * sizeof(struct _tx_desc)) {
|
|
|
|
g_rx = (struct _rx_desc*)((unsigned long)net_dma_start_addr + (CTX_BUFFER_NUM + CRX_BUFFER_NUM) * CBUFFER_SIZE);
|
|
g_tx = (struct _tx_desc*)((char *)g_rx + CRX_BUFFER_NUM * sizeof(struct _rx_desc));
|
|
} else {
|
|
printf("Error!! Ethernet DMA size is smaller");
|
|
goto error_out;
|
|
}
|
|
gS->rx = g_rx;
|
|
gS->tx = g_tx;
|
|
tx_start = net_dma_start_addr;
|
|
rx_start = net_dma_start_addr + CTX_BUFFER_NUM * CBUFFER_SIZE;
|
|
gS->rx_buf_addr = rx_start;
|
|
gS->tx_buf_addr = tx_start;
|
|
|
|
/* init mStruct */
|
|
gS->current_rx_des = 0;
|
|
gS->current_tx_des = 0;
|
|
gS->rx_len = CRX_BUFFER_NUM;
|
|
gS->tx_len = CTX_BUFFER_NUM;
|
|
gS->buffer_len = CBUFFER_SIZE;
|
|
gS->rx_frame_num = 0;
|
|
gS->current_tx_ready = 0;
|
|
gS->last_tx_sent = 0;
|
|
gS->last_tx_desc_num = 0;
|
|
gS->irq_handle = -1;
|
|
gS->linked = 0;
|
|
|
|
if (g_debug > 1) {
|
|
printf("netdma:[0x%lx-0x%lx]\n", net_dma_start_addr, net_dma_end_addr);
|
|
printf("tx_buf_num:%d \t rx_buf_num:%d buf_size:%d\n", CTX_BUFFER_NUM, CRX_BUFFER_NUM, CBUFFER_SIZE);
|
|
printf("[===dma_tx] 0x%lx-0x%lx\n", tx_start, rx_start);
|
|
printf("[===dma_rx] 0x%lx-0x%lx\n", rx_start,(unsigned long) g_rx);
|
|
}
|
|
/* init RX desc */
|
|
pRDesc = gS->rx;
|
|
bufptr = (unsigned char *) gS->rx_buf_addr;
|
|
for (i = 0; i < gS->rx_len - 1; i++) {
|
|
if (g_debug > 1) {
|
|
printf("[rx-descriptor%d] %p\n", i, bufptr);
|
|
}
|
|
pRDesc->rdes0 = RDES0_OWN;
|
|
pRDesc->rdes1 = RDES1_RCH | (gS->buffer_len & RDES1_RBS1_MASK);
|
|
pRDesc->rdes2 = (unsigned long)bufptr;
|
|
pRDesc->rdes3 = (unsigned long)pRDesc + sizeof(struct _rx_desc);
|
|
pRDesc->reverse[0] = 0;
|
|
pRDesc->reverse[1] = 0;
|
|
pRDesc->reverse[2] = 0;
|
|
pRDesc->reverse[3] = 0;
|
|
bufptr += gS->buffer_len;
|
|
pRDesc = pRDesc + 1;
|
|
|
|
}
|
|
pRDesc->rdes0 = RDES0_OWN;
|
|
pRDesc->rdes1 = RDES1_RCH | RDES1_RER | (gS->buffer_len & RDES1_RBS1_MASK); //chain buf
|
|
pRDesc->rdes2 = (unsigned long)bufptr;
|
|
pRDesc->rdes3 = (unsigned long)gS->rx; //circle
|
|
_dcache_flush_range_for_net(( unsigned long )gS->rx, (unsigned long)gS->rx + sizeof(struct _rx_desc)*gS->rx_len);
|
|
_dcache_flush_range_for_net(( unsigned long )gS->rx_buf_addr, (unsigned long)gS->rx_buf_addr + CRX_BUFFER_NUM * CBUFFER_SIZE);
|
|
|
|
/* init TX desc */
|
|
pTDesc = (struct _tx_desc *)gS->tx;
|
|
bufptr = (unsigned char *)gS->tx_buf_addr;
|
|
for (i = 0; i < gS->tx_len - 1; i++) {
|
|
if (g_debug > 1) {
|
|
printf("[tx-descriptor%d] %p\n", i, bufptr);
|
|
}
|
|
pTDesc->tdes0 = 0;
|
|
pTDesc->tdes1 = TDES1_TCH | TDES1_IC;
|
|
pTDesc->tdes2 = (unsigned long)bufptr;
|
|
pTDesc->tdes3 = (unsigned long)pTDesc + sizeof(struct _tx_desc);
|
|
pTDesc->reverse[0] = 0;
|
|
pTDesc->reverse[1] = 0;
|
|
pTDesc->reverse[2] = 0;
|
|
pTDesc->reverse[3] = 0;
|
|
bufptr += gS->buffer_len;
|
|
pTDesc = pTDesc + 1;
|
|
}
|
|
pTDesc->tdes0 = 0;
|
|
pTDesc->tdes1 = TDES1_TCH | TDES1_TER | TDES1_IC; //chain buf, enable complete interrupt
|
|
pTDesc->tdes2 = (unsigned long)bufptr;
|
|
pTDesc->tdes3 = (unsigned long)gS->tx; //circle
|
|
g_current_tx = gS->tx;
|
|
_dcache_flush_range_for_net((unsigned long)gS->tx, (unsigned long)gS->tx + sizeof(struct _tx_desc)*gS->tx_len);
|
|
_dcache_flush_range_for_net(( unsigned long )gS->tx_buf_addr, (unsigned long)gS->tx_buf_addr + CTX_BUFFER_NUM * CBUFFER_SIZE);
|
|
|
|
/* get mii interface */
|
|
g_mac_mode = (aml_eth_readl(PREG_ETH_REG0) & 0x1) ? MAC_MODE_RGMII:MAC_MODE_RMII_CLK_EXTERNAL;
|
|
|
|
/* mac and phy reset */
|
|
eth_reset(gS);
|
|
|
|
/* set mac addr */
|
|
eth_getenv_enetaddr("ethaddr", g_bi_enetaddr);
|
|
set_mac_addrs(g_bi_enetaddr);
|
|
|
|
/* get the mac and ip */
|
|
printf("MAC address is %02x:%02x:%02x:%02x:%02x:%02x\n", g_bi_enetaddr[0], g_bi_enetaddr[1],
|
|
g_bi_enetaddr[2], g_bi_enetaddr[3], g_bi_enetaddr[4], g_bi_enetaddr[5]);
|
|
|
|
/* start the dma para, but don't start the receive dma */
|
|
aml_eth_writel(ETH_DMA_6_Operation_Mode_EFC | ETH_DMA_6_Operation_Mode_TTC_16 | ETH_DMA_6_Operation_Mode_RSF | ETH_DMA_6_Operation_Mode_TSF | ETH_DMA_6_Operation_Mode_DT, ETH_DMA_6_Operation_Mode);
|
|
// | ETH_DMA_6_Operation_Mode_RTC_32 | ETH_DMA_6_Operation_Mode_FUF
|
|
|
|
netdev_chk();
|
|
DMARXStart();
|
|
|
|
g_nInitialized = 1;
|
|
return 0;
|
|
|
|
error_out:
|
|
return -1;
|
|
}
|
|
|
|
int aml_eth_init(bd_t *bis)
|
|
{
|
|
struct eth_device *dev;
|
|
dev = (struct eth_device *)malloc(sizeof(*dev));
|
|
memset(dev, 0, sizeof(*dev));
|
|
sprintf(dev->name, "Meson_Ethernet");
|
|
dev->init = aml_ethernet_init;
|
|
dev->halt = aml_eth_halt;
|
|
dev->send = aml_eth_send;
|
|
dev->recv = aml_eth_rx;
|
|
return eth_register(dev);
|
|
}
|
|
|
|
static int do_phyreg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
unsigned int phyad, reg, value;
|
|
unsigned char *cmd = NULL;
|
|
unsigned int i;
|
|
|
|
if (argc < 2) {
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
|
|
phyad = detect_phyad();
|
|
if (phyad > 32 || phyad < 0) {
|
|
return -1;
|
|
}
|
|
|
|
cmd = (unsigned char *)argv[1];
|
|
switch (*cmd) {
|
|
case 'd':
|
|
printf("=== ethernet phy register dump:\n");
|
|
for (i = 0; i < 32; i++)
|
|
printf("[reg_%d] 0x%x\n", i, phy_reg_rd(phyad, i));
|
|
break;
|
|
case 'r':
|
|
if (argc != 3) {
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
printf("=== ethernet phy register read:\n");
|
|
reg = simple_strtoul(argv[2], NULL, 10);
|
|
printf("[reg_%d] 0x%x\n", reg, phy_reg_rd(phyad, reg));
|
|
|
|
break;
|
|
case 'w':
|
|
if (argc != 4) {
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
printf("=== ethernet phy register write:\n");
|
|
reg = simple_strtoul(argv[2], NULL, 10);
|
|
value = simple_strtoul(argv[3], NULL, 16);
|
|
phy_reg_wr(phyad, reg, value);
|
|
printf("[reg_%d] 0x%x\n", reg, phy_reg_rd(phyad, reg));
|
|
break;
|
|
|
|
default:
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int do_macreg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
unsigned int reg, value;
|
|
unsigned char *cmd = NULL;
|
|
unsigned int i = 0;
|
|
|
|
if (argc < 2) {
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
|
|
cmd = (unsigned char *)argv[1];
|
|
switch (*cmd) {
|
|
case 'd':
|
|
printf("=== ETH_MAC register dump:\n");
|
|
//for (i = 0x0000; i <= 0x00FC; i += 0x4)
|
|
for (i = 0x0000; i <= 0x004C; i += 0x4)
|
|
printf("[0x%04x] 0x%lx\n", i, (unsigned long)aml_eth_readl(ETH_BASE + i));
|
|
#if 0
|
|
printf("=== ETH_MMC register dump:\n");
|
|
for (i = 0x0100; i <= 0x0284; i += 0x4)
|
|
printf("[0x%04x] 0x%x\n", i, aml_eth_readl(ETH_BASE + i));
|
|
#endif
|
|
printf("=== ETH_DMA register dump:\n");
|
|
for (i = 0x1000; i <= 0x1054; i += 0x4)
|
|
printf("[0x%04x] 0x%x\n", i, (unsigned int)aml_eth_readl(ETH_BASE + i));
|
|
|
|
printf("=== ethernet board config register dump:\n");
|
|
printf("[0x1076] 0x%x\n", READ_CBUS_REG(0x1076));
|
|
printf("[0x2032] 0x%x\n", READ_CBUS_REG(0x2032));
|
|
printf("[0x2042] 0x%x\n", READ_CBUS_REG(0x2042));
|
|
break;
|
|
case 'r':
|
|
if (argc != 3) {
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
printf("=== ethernet mac register read:\n");
|
|
reg = simple_strtoul(argv[2], NULL, 10);
|
|
printf("[0x%04x] 0x%x\n", i, (unsigned int)aml_eth_readl(ETH_BASE + reg));
|
|
|
|
break;
|
|
case 'w':
|
|
if (argc != 4) {
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
printf("=== ethernet mac register write:\n");
|
|
reg = simple_strtoul(argv[2], NULL, 10);
|
|
value = simple_strtoul(argv[3], NULL, 16);
|
|
aml_eth_writel(value, ETH_BASE + reg);
|
|
printf("[0x%04x] 0x%x\n", reg, value);
|
|
break;
|
|
|
|
default:
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int do_cbusreg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
unsigned int reg, value;
|
|
char *cmd = NULL;
|
|
|
|
|
|
if (argc < 3) {
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
|
|
cmd = argv[1];
|
|
switch (*cmd) {
|
|
case 'r':
|
|
if (argc != 3) {
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
printf("=== cbus register read:\n");
|
|
reg = simple_strtoul(argv[2], NULL, 16);
|
|
printf("[0x%04x] 0x%x\n", reg, READ_CBUS_REG(reg));
|
|
|
|
break;
|
|
case 'w':
|
|
if (argc != 4) {
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
printf("=== cbus register write:\n");
|
|
reg = simple_strtoul(argv[2], NULL, 16);
|
|
value = simple_strtoul(argv[3], NULL, 16);
|
|
WRITE_CBUS_REG(reg, value);
|
|
printf("[0x%04x] 0x%x\n", reg, READ_CBUS_REG(reg));
|
|
break;
|
|
|
|
default:
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//loopback test.
|
|
static int do_autoping(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
unsigned int phyad = -1;
|
|
unsigned int value;
|
|
char buffer[40];
|
|
|
|
if (argc < 2) {
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
|
|
phyad = detect_phyad();
|
|
if (phyad > 32 || phyad < 0) {
|
|
return -1;
|
|
}
|
|
|
|
value = phy_reg_rd(phyad, PHY_CR);
|
|
phy_reg_wr(phyad, PHY_CR, value | (1 << 14)); //phy loopback
|
|
while (1) {
|
|
if (had_ctrlc()) {
|
|
printf("Quit autoping...\n");
|
|
return 0;
|
|
}
|
|
snprintf(buffer, sizeof(buffer), "ping %s ", argv[1]);
|
|
run_command(buffer, 0);
|
|
}
|
|
return 0;
|
|
}
|
|
static int do_mdc_clk(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
if (argc < 2) {
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
|
|
g_mdc_clock_range=((simple_strtoul(argv[1], NULL, 16)&0xf)<<2);
|
|
printf("set value:0x%x\n",g_mdc_clock_range);
|
|
return 0;
|
|
}
|
|
int do_ethchk(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
netdev_chk();
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int do_ethrst(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
eth_reset(gS);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int do_ethmode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
unsigned char *cmd = NULL;
|
|
|
|
if (argc < 2) {
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
|
|
cmd = (unsigned char *)argv[1];
|
|
switch (*cmd) {
|
|
case '0':
|
|
g_mac_mode = 0;
|
|
printf("set MAC mode: RMII 100/10 Mbps (external clk).\n");
|
|
break;
|
|
case '1':
|
|
g_mac_mode = 1;
|
|
printf("set MAC mode: RMII 100/10 Mbps (internal clk).\n");
|
|
break;
|
|
case '2':
|
|
g_mac_mode = 2;
|
|
printf("set MAC mode: RGMII 1000/100/10 Mbps.\n");
|
|
break;
|
|
|
|
default:
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
if (get_cpuid() >= 0x16) {
|
|
/* config ethernet mode */
|
|
switch (g_mac_mode) {
|
|
case MAC_MODE_RMII_CLK_EXTERNAL:
|
|
if (get_cpuid() == 0x19) {
|
|
//WRITE_CBUS_REG(HHI_ETH_CLK_CNTL, 0xf00);
|
|
//WRITE_CBUS_REG(PERIPHS_PIN_MUX_6, 0x0000fde0);
|
|
//WRITE_CBUS_REG(PREG_ETHERNET_ADDR0, 0x241);
|
|
}
|
|
else{
|
|
//WRITE_CBUS_REG(HHI_ETH_CLK_CNTL, 0x130); //clock phase invert
|
|
//WRITE_CBUS_REG(PERIPHS_PIN_MUX_6, 0x8007ffe0);
|
|
//WRITE_CBUS_REG(PREG_ETHERNET_ADDR0, 0x241);
|
|
}
|
|
break;
|
|
case MAC_MODE_RMII_CLK_INTERNAL:
|
|
//WRITE_CBUS_REG(HHI_ETH_CLK_CNTL, 0x702);
|
|
//WRITE_CBUS_REG(PERIPHS_PIN_MUX_6, 0x4007ffe0);
|
|
//WRITE_CBUS_REG(PREG_ETHERNET_ADDR0, 0x241);
|
|
break;
|
|
case MAC_MODE_RGMII:
|
|
//WRITE_CBUS_REG(HHI_ETH_CLK_CNTL, 0x309);
|
|
//WRITE_CBUS_REG(PERIPHS_PIN_MUX_6, 0x4007ffe0);
|
|
//WRITE_CBUS_REG(PREG_ETHERNET_ADDR0, 0x211);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
udelay(1000);
|
|
//hardware_reset();
|
|
eth_reset(gS);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int do_ethdbg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
unsigned char *cmd = NULL;
|
|
|
|
if (argc < 2) {
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
|
|
cmd = (unsigned char *)argv[1];
|
|
switch (*cmd) {
|
|
case '0':
|
|
g_debug = 0;
|
|
break;
|
|
case '1':
|
|
g_debug = 1;
|
|
break;
|
|
case '2':
|
|
g_debug = 2;
|
|
break;
|
|
case '3':
|
|
g_debug = 3;
|
|
break;
|
|
case '4':
|
|
g_debug = 4;
|
|
break;
|
|
|
|
default:
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
printf("set ethernet debug: %d\n", g_debug);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int do_netspeed(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
int speed=100;
|
|
int full=0;
|
|
int data=0;
|
|
|
|
if (argc < 2) {
|
|
|
|
switch (g_phy_Identifier)
|
|
{
|
|
case PHY_ATHEROS_8032:
|
|
break;
|
|
case PHY_IC_IP101ALF:
|
|
break;
|
|
case PHY_SMSC_8700:
|
|
default:
|
|
data = phy_reg_rd(1,31);
|
|
speed = data & (1<<3);
|
|
full = ((data >>4) & 1);
|
|
printf("status: %sM %s-duplex\n",(speed?"100":"10"),(full?"full":"half"));
|
|
break;
|
|
}
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
speed = simple_strtoul(argv[1], NULL, 10);
|
|
if ((speed != 0) && (speed != 100) && (speed != 10)) return -1;
|
|
data= phy_reg_rd(1,0);
|
|
if (speed == 0) //disable net speed enforce mode,ie. we enable A/N
|
|
{
|
|
g_speed_enforce=0;
|
|
data |=(1<<12)|(1<<9);
|
|
}else{
|
|
g_speed_enforce=1;
|
|
data &=~(1<<12);
|
|
if (speed == 100) //100M
|
|
{
|
|
data |= (1<<13) ;
|
|
}else if(speed == 10 ){ //10M
|
|
data &=~(1<<13);
|
|
}
|
|
if (strncmp(argv[2],"fu",2) == 0)
|
|
{
|
|
data |= (1<<8);
|
|
}else{
|
|
data &=~(1<<8);
|
|
}
|
|
}
|
|
phy_reg_wr(1, 0, data);
|
|
return 0;
|
|
|
|
}
|
|
#ifdef CONFIG_M8B
|
|
static int do_eth_cali(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|
{
|
|
unsigned int value;
|
|
int rise=0;
|
|
int sel=0;
|
|
int i;
|
|
//char *cmd = NULL;
|
|
|
|
|
|
if (argc < 2) {
|
|
return cmd_usage(cmdtp);
|
|
}
|
|
rise = simple_strtoul(argv[1], NULL, 10);
|
|
sel = simple_strtoul(argv[2], NULL, 10);
|
|
eth_aml_reg0_t eth_reg0;
|
|
eth_reg0.d32 = READ_CBUS_REG(0x2050);
|
|
eth_reg0.b.cali_start = 1;
|
|
eth_reg0.b.cali_rise = rise;
|
|
eth_reg0.b.cali_sel = sel;
|
|
WRITE_CBUS_REG(0x2050, eth_reg0.d32);
|
|
printf("0x%x\n", READ_CBUS_REG(0x2050));
|
|
for (i=0;i<10000;i++) {
|
|
value = READ_CBUS_REG(0x2051);
|
|
if ((value>>15)&0x1)
|
|
printf("value == %x, cali_len == %d, cali_idx == %d, cali_sel =%d, cali_rise = %d\n",value,(value>>5)&0x1f,(value&0x1f),(value>>11)&0x7,(value>>14)&0x1);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
U_BOOT_CMD(
|
|
cali, 3, 1, do_eth_cali,
|
|
"configure clock phase",
|
|
" - phase mac clock.\n"
|
|
);
|
|
#endif
|
|
|
|
U_BOOT_CMD(
|
|
netspd_f, 3, 1, do_netspeed,
|
|
"enforce eth speed",
|
|
"0 - disable enforce mode,enable A/N\n"
|
|
"10 full - enforce 10M full duplex mode\n"
|
|
"10 half - enforce 10M half duplex mode\n"
|
|
"100 full - enforce 100M full duplexmode\n"
|
|
"100 half - enforce 100M half duplexmode\n"
|
|
);
|
|
U_BOOT_CMD(
|
|
phyreg, 4, 1, do_phyreg,
|
|
"ethernet phy register read/write/dump",
|
|
"d - dump phy registers\n"
|
|
" r reg - read phy register\n"
|
|
" w reg val - write phy register"
|
|
);
|
|
|
|
U_BOOT_CMD(
|
|
macreg, 4, 1, do_macreg,
|
|
"ethernet mac register read/write/dump",
|
|
"d - dump mac registers\n"
|
|
" r reg - read mac register\n"
|
|
" w reg val - write mac register"
|
|
);
|
|
|
|
U_BOOT_CMD(
|
|
cbusreg, 4, 1, do_cbusreg,
|
|
"cbus register read/write",
|
|
"r reg - read cbus register\n"
|
|
" w reg val - write cbus register"
|
|
);
|
|
U_BOOT_CMD(
|
|
mdc_clk, 2, 1, do_mdc_clk,
|
|
"do mdc clock",
|
|
"mdc data-- data is ETH_MAC_4_GMII_Addr[2..5] "
|
|
);
|
|
U_BOOT_CMD(
|
|
autoping, 2, 1, do_autoping,
|
|
"do auto ping test",
|
|
"ip"
|
|
);
|
|
|
|
U_BOOT_CMD(
|
|
ethchk, 1, 1, do_ethchk,
|
|
"check ethernet status",
|
|
""
|
|
);
|
|
|
|
U_BOOT_CMD(
|
|
ethrst, 1, 1, do_ethrst,
|
|
"reset ethernet phy",
|
|
" - reset etherent phy\n"
|
|
);
|
|
|
|
U_BOOT_CMD(
|
|
ethmode, 2, 1, do_ethmode,
|
|
"set ethernet mac mode",
|
|
"0 - set mac mode RMII (external clk).\n"
|
|
" 1 - set mac mode RMII (internal clk).\n"
|
|
" 2 - set mac mode RGMII.\n"
|
|
);
|
|
|
|
U_BOOT_CMD(
|
|
ethdbg, 2, 1, do_ethdbg,
|
|
"set ethernet debug level",
|
|
"0 - disable ethernet debug\n"
|
|
" 1 - ethernet basic info\n"
|
|
" 2 - ethernet TX debug\n"
|
|
" 3 - ethernet RX debug\n"
|
|
" 4 - ethernet TX/RX debug\n"
|
|
);
|
|
|