Cubieboard的U-boot以太网驱动移植

网上发现一段话
Allwinner A10 has an ethernet controller that seem to be developped
internally by them.
The exact feature set of this controller is unknown, since there is no
public documentation for this IP, and this driver is mostly the one
published by Allwinner that has been heavily cleaned up.
意思是说,A10内部的以太网控制器只是被allwinner内部开发过,控制器的功能未知,没有公布有关说明文档,
为什么?难道跟IP核的版权有关???
反正我一直没有找到关于A10的WEMAC描述文档,用户手册里面也没有
我想一定有支持A10网络的U-boot,但是我没找到U-boot源代码
最后在网上找到了一段u-boot下的网络驱动代码,准备把它移植到我手上的U-boot中去,实现网络支持
这个驱动的作者没有署名,感谢作者分享代码。
实现过程跟我之前写的一篇文章原理基本一致 http://blog.csdn.net/andy_wsj/article/details/8747350,就不再分析了。直接移植,并测试之。

硬件环境:笔记本,cubieboard,USB转串口线,microSD卡+读卡器,网线两根,路由器一个
软件环境:REHL5,编译器arm-none-eabi-版本4.7.2
准备工作:实现SD卡启动 http://blog.csdn.net/andy_wsj/article/details/8515197,方便测试

一、移植过程:
1、目录u-boot-sunxi-sunxi/drivers/net/sunxi_wemac.c b/drivers/net/

增加文件sunxi_wemac.c,来源网上,弄不了附件,只好粘贴源码拉:

/*
 * sunxi_wemac.c -- Allwinner A10 ethernet driver
 *
 * (C) Copyright 2012, Stefan Roese
 *
 * This program 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 of the License, or
 * (at your option) any later version.
 *
 * This program 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.
 */


#include
#include
#include
#include
#include
#include
#include
#include


/* EMAC register  */
struct wemac_regs {
u32 ctl;    /* 0x00 */
u32 tx_mode; /* 0x04 */
u32 tx_flow; /* 0x08 */
u32 tx_ctl0; /* 0x0c */
u32 tx_ctl1; /* 0x10 */
u32 tx_ins;  /* 0x14 */
u32 tx_pl0;  /* 0x18 */
u32 tx_pl1;  /* 0x1c */
u32 tx_sta;  /* 0x20 */
u32 tx_io_data;/* 0x24 */
u32 tx_io_data1; /* 0x28 */
u32 tx_tsvl0; /* 0x2c */
u32 tx_tsvh0; /* 0x30 */
u32 tx_tsvl1; /* 0x34 */
u32 tx_tsvh1; /* 0x38 */
u32 rx_ctl;  /* 0x3c */
u32 rx_hash0; /* 0x40 */
u32 rx_hash1; /* 0x44 */
u32 rx_sta;  /* 0x48 */
u32 rx_io_data;/* 0x4c */
u32 rx_fbc;  /* 0x50 */
u32 int_ctl; /* 0x54 */
u32 int_sta; /* 0x58 */
u32 mac_ctl0; /* 0x5c */
u32 mac_ctl1; /* 0x60 */
u32 mac_ipgt; /* 0x64 */
u32 mac_ipgr; /* 0x68 */
u32 mac_clrt; /* 0x6c */
u32 mac_maxf; /* 0x70 */
u32 mac_supp; /* 0x74 */
u32 mac_test; /* 0x78 */
u32 mac_mcfg; /* 0x7c */
u32 mac_mcmd; /* 0x80 */
u32 mac_madr; /* 0x84 */
u32 mac_mwtd; /* 0x88 */
u32 mac_mrdd; /* 0x8c */
u32 mac_mind; /* 0x90 */
u32 mac_ssrr; /* 0x94 */
u32 mac_a0;  /* 0x98 */
u32 mac_a1;  /* 0x9c */
};


/* SRAMC register  */
struct sunxi_sramc_regs {
u32 ctrl0;
u32 ctrl1;
};


/* 0: Disable       1: Aborted frame enable(default) */
#define EMAC_TX_AB_M (0x1 << 0)
/* 0: CPU           1: DMA(default) */
#define EMAC_TX_TM (0x1 << 1)


#define EMAC_TX_SETUP (0)


/* 0: DRQ asserted  1: DRQ automatically(default) */
#define EMAC_RX_DRQ_MODE (0x1 << 1)
/* 0: CPU           1: DMA(default) */
#define EMAC_RX_TM (0x1 << 2)
/* 0: Normal(default)        1: Pass all Frames */
#define EMAC_RX_PA (0x1 << 4)
/* 0: Normal(default)        1: Pass Control Frames */
#define EMAC_RX_PCF (0x1 << 5)
/* 0: Normal(default)        1: Pass Frames with CRC Error */
#define EMAC_RX_PCRCE (0x1 << 6)
/* 0: Normal(default)        1: Pass Frames with Length Error */
#define EMAC_RX_PLE (0x1 << 7)
/* 0: Normal                 1: Pass Frames length out of range(default) */
#define EMAC_RX_POR (0x1 << 8)
/* 0: Not accept             1: Accept unicast Packets(default) */
#define EMAC_RX_UCAD (0x1 << 16)
/* 0: Normal(default)        1: DA Filtering */
#define EMAC_RX_DAF (0x1 << 17)
/* 0: Not accept             1: Accept multicast Packets(default) */
#define EMAC_RX_MCO (0x1 << 20)
/* 0: Disable(default)       1: Enable Hash filter */
#define EMAC_RX_MHF (0x1 << 21)
/* 0: Not accept             1: Accept Broadcast Packets(default) */
#define EMAC_RX_BCO (0x1 << 22)
/* 0: Disable(default)       1: Enable SA Filtering */
#define EMAC_RX_SAF (0x1 << 24)
/* 0: Normal(default)        1: Inverse Filtering */
#define EMAC_RX_SAIF (0x1 << 25)


#define EMAC_RX_SETUP (EMAC_RX_POR | EMAC_RX_UCAD | EMAC_RX_DAF | \
EMAC_RX_MCO | EMAC_RX_BCO)


/* 0: Disable                1: Enable Receive Flow Control(default) */
#define EMAC_MAC_CTL0_RFC (0x1 << 2)
/* 0: Disable                1: Enable Transmit Flow Control(default) */
#define EMAC_MAC_CTL0_TFC (0x1 << 3)


#define EMAC_MAC_CTL0_SETUP (EMAC_MAC_CTL0_RFC | EMAC_MAC_CTL0_TFC)


/* 0: Disable                1: Enable MAC Frame Length Checking(default) */
#define EMAC_MAC_CTL1_FLC (0x1 << 1)
/* 0: Disable(default)       1: Enable Huge Frame */
#define EMAC_MAC_CTL1_HF (0x1 << 2)
/* 0: Disable(default)       1: Enable MAC Delayed CRC */
#define EMAC_MAC_CTL1_DCRC (0x1 << 3)
/* 0: Disable                1: Enable MAC CRC(default) */
#define EMAC_MAC_CTL1_CRC (0x1 << 4)
/* 0: Disable                1: Enable MAC PAD Short frames(default) */
#define EMAC_MAC_CTL1_PC (0x1 << 5)
/* 0: Disable(default)       1: Enable MAC PAD Short frames and append CRC */
#define EMAC_MAC_CTL1_VC (0x1 << 6)
/* 0: Disable(default)       1: Enable MAC auto detect Short frames */
#define EMAC_MAC_CTL1_ADP (0x1 << 7)
/* 0: Disable(default)       1: Enable */
#define EMAC_MAC_CTL1_PRE (0x1 << 8)
/* 0: Disable(default)       1: Enable */
#define EMAC_MAC_CTL1_LPE (0x1 << 9)
/* 0: Disable(default)       1: Enable no back off */
#define EMAC_MAC_CTL1_NB (0x1 << 12)
/* 0: Disable(default)       1: Enable */
#define EMAC_MAC_CTL1_BNB (0x1 << 13)
/* 0: Disable(default)       1: Enable */
#define EMAC_MAC_CTL1_ED (0x1 << 14)


#define EMAC_MAC_CTL1_SETUP (EMAC_MAC_CTL1_FLC | EMAC_MAC_CTL1_CRC | \
EMAC_MAC_CTL1_PC)


#define EMAC_MAC_IPGT 0x15


#define EMAC_MAC_NBTB_IPG1 0xC
#define EMAC_MAC_NBTB_IPG2 0x12


#define EMAC_MAC_CW 0x37
#define EMAC_MAC_RM 0xF


#define EMAC_MAC_MFL 0x0600


/* Receive status */
#define EMAC_CRCERR (1 << 4)
#define EMAC_LENERR (3 << 5)


#define DMA_CPU_TRRESHOLD 2000


struct wemac_eth_dev {
u32 speed;
u32 duplex;
u32 phy_configured;
int link_printed;
};


struct wemac_rxhdr {
s16 rx_len;
u16 rx_status;
};


static void wemac_inblk_32bit(void *reg, void *data, int count)
{
int cnt = (count + 3) >> 2;


if (cnt) {
u32 *buf = data;


do {
u32 x = readl(reg);
*buf++ = x;
} while (--cnt);
}
}


static void wemac_outblk_32bit(void *reg, void *data, int count)
{
int cnt = (count + 3) >> 2;


if (cnt) {
const u32 *buf = data;


do {
writel(*buf++, reg);
} while (--cnt);
}
}


/*
 * Read a word from phyxcer
 */
static int wemac_phy_read(const char *devname, unsigned char addr,
 unsigned char reg, unsigned short *value)
{
struct eth_device *dev = eth_get_dev_by_name(devname);
struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;


/* issue the phy address and reg */
writel(addr << 8 | reg, ®s->mac_madr);


/* pull up the phy io line */
writel(0x1, ®s->mac_mcmd);


/* Wait read complete */
mdelay(1);


/* push down the phy io line */
writel(0x0, ®s->mac_mcmd);


/* and write data */
*value = readl(®s->mac_mrdd);


return 0;
}


/*
 * Write a word to phyxcer
 */
static int wemac_phy_write(const char *devname, unsigned char addr,
  unsigned char reg, unsigned short value)
{
struct eth_device *dev = eth_get_dev_by_name(devname);
struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;


/* issue the phy address and reg */
writel(addr << 8 | reg, ®s->mac_madr);


/* pull up the phy io line */
writel(0x1, ®s->mac_mcmd);


/* Wait write complete */
mdelay(1);


/* push down the phy io line */
writel(0x0, ®s->mac_mcmd);


/* and write data */
writel(value, ®s->mac_mwtd);


return 0;
}


static void emac_setup(struct eth_device *dev)
{
struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
u32 reg_val;
u16 phy_val;
u32 duplex_flag;


/* Set up TX */
writel(EMAC_TX_SETUP, ®s->tx_mode);


/* Set up RX */
writel(EMAC_RX_SETUP, ®s->rx_ctl);


/* Set MAC */
/* Set MAC CTL0 */
writel(EMAC_MAC_CTL0_SETUP, ®s->mac_ctl0);


/* Set MAC CTL1 */
wemac_phy_read(dev->name, 1, 0, &phy_val);
debug("PHY SETUP, reg 0 value: %x\n", phy_val);
duplex_flag = !!(phy_val & (1 << 8));


reg_val = 0;
if (duplex_flag)
reg_val = (0x1 << 0);
writel(EMAC_MAC_CTL1_SETUP | reg_val, ®s->mac_ctl1);


/* Set up IPGT */
writel(EMAC_MAC_IPGT, ®s->mac_ipgt);


/* Set up IPGR */
writel(EMAC_MAC_NBTB_IPG2 | (EMAC_MAC_NBTB_IPG1 << 8), ®s->mac_ipgr);


/* Set up Collison window */
writel(EMAC_MAC_RM | (EMAC_MAC_CW << 8), ®s->mac_clrt);


/* Set up Max Frame Length */
writel(EMAC_MAC_MFL, ®s->mac_maxf);
}


static void wemac_reset(struct eth_device *dev)
{
struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;


debug("resetting device\n");


/* RESET device */
writel(0, ®s->ctl);
udelay(200);


writel(1, ®s->ctl);
udelay(200);
}


static int sunxi_wemac_eth_init(struct eth_device *dev, bd_t *bd)
{
struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
struct wemac_eth_dev *priv = dev->priv;
u16 phy_reg;


/* Init EMAC */


/* Flush RX FIFO */
setbits_le32(®s->rx_ctl, 0x8);
udelay(1);


/* Init MAC */


/* Soft reset MAC */
clrbits_le32(®s->mac_ctl0, 1 << 15);


/* Set MII clock */
clrsetbits_le32(®s->mac_mcfg, 0xf << 2, 0xd << 2);


/* Clear RX counter */
writel(0x0, ®s->rx_fbc);
udelay(1);


/* Set up EMAC */
emac_setup(dev);


writel(dev->enetaddr[0] << 16 | dev->enetaddr[1] << 8 |
      dev->enetaddr[2], ®s->mac_a1);
writel(dev->enetaddr[3] << 16 | dev->enetaddr[4] << 8 |
      dev->enetaddr[5], ®s->mac_a0);


mdelay(1);


wemac_reset(dev);


/* PHY POWER UP */
wemac_phy_read(dev->name, 1, 0, &phy_reg);
wemac_phy_write(dev->name, 1, 0, phy_reg & (~(1 << 11)));
mdelay(1);


wemac_phy_read(dev->name, 1, 0, &phy_reg);


priv->speed  = miiphy_speed(dev->name, 0);
priv->duplex = miiphy_duplex(dev->name, 0);


/* Print link status only once */
if (!priv->link_printed) {
printf("ENET Speed is %d Mbps - %s duplex connection\n",
      priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL");
priv->link_printed = 1;
}


/* Set EMAC SPEED depend on PHY */
clrsetbits_le32(®s->mac_supp, 1 << 8,
((phy_reg & (1 << 13)) >> 13) << 8);


/* Set duplex depend on phy */
clrsetbits_le32(®s->mac_ctl1, 1 << 0,
((phy_reg & (1 << 8)) >> 8) << 0);


/* Enable RX/TX */
setbits_le32(®s->ctl, 0x7);


return 0;
}


static void sunxi_wemac_eth_halt(struct eth_device *dev)
{
/* Nothing to do here */
}


static int sunxi_wemac_eth_recv(struct eth_device *dev)
{
struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
struct wemac_rxhdr rxhdr;
u32 rxcount;
u32 reg_val;
int rx_len;
int rx_status;
int good_packet;


/* Check packet ready or not */


/*
* Race warning: The first packet might arrive with
* the interrupts disabled, but the second will fix
*/
rxcount = readl(®s->rx_fbc);
if (!rxcount) {
/* Had one stuck? */
rxcount = readl(®s->rx_fbc);
if (!rxcount)
return 0;
}


reg_val = readl(®s->rx_io_data);
if (reg_val != 0x0143414d) {
/* Disable RX */
clrbits_le32(®s->ctl, 1 << 2);


/* Flush RX FIFO */
setbits_le32(®s->rx_ctl, 1 << 3);
while (readl(®s->rx_ctl) & (1 << 3))
;


/* Enable RX */
setbits_le32(®s->ctl, 1 << 2);


return 0;
}


/*
* A packet ready now
* Get status/length
*/
good_packet = 1;


wemac_inblk_32bit(®s->rx_io_data, &rxhdr, sizeof(rxhdr));


rx_len = rxhdr.rx_len;
rx_status = rxhdr.rx_status;


/* Packet Status check */
if (rx_len < 0x40) {
good_packet = 0;
debug("RX: Bad Packet (runt)\n");
}


/* rx_status is identical to RSR register. */
if (0 & rx_status & (EMAC_CRCERR | EMAC_LENERR)) {
good_packet = 0;
if (rx_status & EMAC_CRCERR)
printf("crc error\n");
if (rx_status & EMAC_LENERR)
printf("length error\n");
}


/* Move data from WEMAC */
if (good_packet) {
if (rx_len > DMA_CPU_TRRESHOLD) {
printf("Received packet is too big (len=%d)\n", rx_len);
} else {
wemac_inblk_32bit((void *)®s->rx_io_data,
 NetRxPackets[0], rx_len);


/* Pass to upper layer */
NetReceive(NetRxPackets[0], rx_len);
return rx_len;
}
}


return 0;
}


static int sunxi_wemac_eth_send(struct eth_device *dev, void *packet, int len)
{
struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;


/* Select channel 0 */
writel(0, ®s->tx_ins);


/* Write packet */
wemac_outblk_32bit((void *)®s->tx_io_data, packet, len);


/* Set TX len */
writel(len, ®s->tx_pl0);


/* Start translate from fifo to phy */
setbits_le32(®s->tx_ctl0, 1);


return 0;
}


int sunxi_wemac_initialize(void)
{
struct sunxi_ccm_reg *const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
struct sunxi_sramc_regs *sram =
(struct sunxi_sramc_regs *)SUNXI_SRAMC_BASE;
struct eth_device *dev;
struct wemac_eth_dev *priv;
int pin;


dev = malloc(sizeof(*dev));
if (dev == NULL)
return -ENOMEM;


priv = (struct wemac_eth_dev *)malloc(sizeof(struct wemac_eth_dev));
if (!priv) {
free(dev);
return -ENOMEM;
}


memset(dev, 0, sizeof(*dev));
memset(priv, 0, sizeof(struct wemac_eth_dev));


/* Map SRAM to EMAC */
setbits_le32(&sram->ctrl1, 0x5 << 2);


/* Configure pin mux settings for MII Ethernet */
for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(17); pin++)
sunxi_gpio_set_cfgpin(pin, 2);


sunxi_gpio_set_cfgpin(SUNXI_GPH(19), 1);
sunxi_gpio_output(SUNXI_GPH(19), 1);


/* Set up clock gating */
setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_EMAC);


dev->iobase = SUNXI_EMAC_BASE;
dev->priv = priv;
dev->init = sunxi_wemac_eth_init;
dev->halt = sunxi_wemac_eth_halt;
dev->send = sunxi_wemac_eth_send;
dev->recv = sunxi_wemac_eth_recv;
strcpy(dev->name, "wemac");


eth_register(dev);


miiphy_register(dev->name, wemac_phy_read, wemac_phy_write);


return 0;
}


修改Makefile,增加一句:
COBJS-$(CONFIG_SUNXI_WEMAC) += sunxi_wemac.o

2、文件u-boot-sunxi-sunxi/include/netdev.h
增加一句:
int sunxi_wemac_initialize(bd_t *bis);


3、文件u-boot-sunxi-sunxi/include/configs/sunxi-common.h
增加如下内容:
/* Ethernet support on A10 */
#define CONFIG_SUNXI_WEMAC
#define CONFIG_MII                      /* MII PHY management           */
#define CONFIG_CMD_MII
#define CONFIG_CMD_NET
#define CONFIG_CMD_PING
#define CONFIG_CMD_DHCP
#define CONFIG_CMD_NFS
#define CONFIG_CMD_SNTP
#define CONFIG_CMD_DNS
#define CONFIG_NETCONSOLE
#define CONFIG_BOOTP_SUBNETMASK
#define CONFIG_BOOTP_GATEWAY
#define CONFIG_BOOTP_HOSTNAME
#define CONFIG_BOOTP_NISDOMAIN
#define CONFIG_BOOTP_BOOTPATH
#define CONFIG_BOOTP_BOOTFILESIZE
#define CONFIG_BOOTP_DNS
#define CONFIG_BOOTP_DNS2
#define CONFIG_BOOTP_SEND_HOSTNAME
#define CONFIG_BOOTP_NTPSERVER
#define CONFIG_BOOTP_TIMEOFFSET
#define CONFIG_BOOTP_MAY_FAIL
#define CONFIG_BOOTP_SERVERIP
#define CONFIG_BOOTP_DHCP_REQUEST_DELAY         50000
#define CONFIG_TIMESTAMP


4、文件u-boot-sunxi-sunxi/arch/arm/cpu/armv7/sunxi/board.c
增加头文件包含:
#include


增加函数:
#if defined(CONFIG_SUNXI_WEMAC)
/*
 * Initializes on-chip ethernet controllers.
 * to override, implement board_eth_init()
 */
int cpu_eth_init(bd_t *bis)
{
        sunxi_wemac_initialize(bis);
        return 0;
}
#endif


5、文件u-boot-sunxi-sunxi/include/status_led.h

由于之前打开了LED,编译时会报错,没有定义启动状态指示灯

如果没有打开LED,这一步略去

定义一下:
#define STATUS_LED_BOOT         ((7 << 5) + 20)   /*set the green one as boot led*/
选择绿色的LED灯作为启动指示灯。
修改
#define STATUS_LED_STATE       STATUS_LED_OFF   //表示上电之后LED熄灭

6、增加U-boot参数

就是设置一下板子的IP,MAC地址和tftp服务器地址,这个可以在参数文件uEnv.txt里面设置

但是我直接写在代码里,先绕过参数文件制作那一块

文件u-boot-sunxi-sunxi/include/configs/sunxi-common.h里面

#define CONFIG_EXTRA_ENV_SETTINGS \
"console=ttyS0,115200\0" \
"root=/dev/mmcblk0p2 rootwait\0" \
"panicarg=panic=10\0" \
"extraargs=\0" \
"loglevel=8\0" \
"ethaddr=11:22:33:44:55:66\0" \
"ipaddr=192.168.1.20\0" \
"serverip=192.168.1.10\0" \

       ..............

增加了3行

"ethaddr=11:22:33:44:55:66\0" \
"ipaddr=192.168.1.20\0" \
"serverip=192.168.1.10\0" \



7、编译、测试


二、测试
1、建立tftp服务器,网上搜索建立方法,很多

2、网络连接
路由器一只,网线二根,直接连接。


3、网络配置

设置好地址


4、简单测试,随便准备一个文件,放到tftp根目录下,我的是/tftpboot

启动u-boot,进入命令模式输入:

ping 192.168.1.10

ping通之后,我把spl/sunxi-spl.bin拷到/tftpboot,执行:

tftp 48000000 sunxi-spl.bin

go 48000000

然后看到执行代码执行了


如果把适合cubieborard的内核uImage拷到/tftpboot

执行上述操作,或者自动执行

那么就可以实现从网络启动linux内核了

这是接下来我准备学习的内容之一










你可能感兴趣的:(u-boot学习)