Merge branch 'master' of git://git.denx.de/u-boot-net

This commit is contained in:
Wolfgang Denk 2009-07-23 19:20:26 +02:00
commit 4fb799aeaf
45 changed files with 1943 additions and 243 deletions

5
README
View file

@ -1184,6 +1184,11 @@ The following options need to be configured:
Defines a default value for the IP address of a TFTP
server to contact when using the "tftboot" command.
CONFIG_KEEP_SERVERADDR
Keeps the server's MAC address, in the env 'serveraddr'
for passing to bootargs (like Linux's netconsole option)
- Multicast TFTP Mode:
CONFIG_MCAST_TFTP

View file

@ -7,6 +7,7 @@
*/
#include <common.h>
#include <netdev.h>
#include <config.h>
#include <command.h>
#include <asm/blackfin.h>
@ -77,3 +78,10 @@ int board_early_init_f(void)
return 0;
}
#ifdef CONFIG_SMC911X
int board_eth_init(bd_t *bis)
{
return smc911x_initialize(0, CONFIG_SMC911X_BASE);
}
#endif

View file

@ -9,6 +9,7 @@
#include <common.h>
#include <config.h>
#include <command.h>
#include <netdev.h>
#include <asm/blackfin.h>
DECLARE_GLOBAL_DATA_PTR;
@ -77,3 +78,12 @@ int board_early_init_f(void)
return 0;
}
int board_eth_init(bd_t *bis)
{
int rc = 0;
#ifdef CONFIG_SMC911X
rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
#endif
return rc;
}

View file

@ -25,6 +25,7 @@
#include <common.h>
#include <netdev.h>
#include <asm/arch/mx31.h>
#include <asm/arch/mx31-regs.h>
@ -61,3 +62,12 @@ int checkboard(void)
printf("Board: i.MX31 MAX PDK (3DS)\n");
return 0;
}
int board_eth_init(bd_t *bis)
{
int rc = 0;
#ifdef CONFIG_SMC911X
rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
#endif
return rc;
}

View file

@ -23,6 +23,7 @@
#include <common.h>
#include <netdev.h>
#include <asm/arch/mx31.h>
#include <asm/arch/mx31-regs.h>
@ -75,3 +76,12 @@ int checkboard (void)
printf("Board: i.MX31 Litekit\n");
return 0;
}
int board_eth_init(bd_t *bis)
{
int rc = 0;
#ifdef CONFIG_SMC911X
rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
#endif
return rc;
}

View file

@ -24,6 +24,7 @@
#include <common.h>
#include <s6e63d6.h>
#include <netdev.h>
#include <asm/arch/mx31.h>
#include <asm/arch/mx31-regs.h>
@ -128,3 +129,12 @@ int checkboard (void)
printf("Board: Phytec phyCore i.MX31\n");
return 0;
}
int board_eth_init(bd_t *bis)
{
int rc = 0;
#ifdef CONFIG_SMC911X
rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
#endif
return rc;
}

View file

@ -18,6 +18,7 @@
*/
#include <common.h>
#include <netdev.h>
#include <asm/io.h>
#include "vct.h"
@ -45,10 +46,11 @@ int ebi_init_smc911x(void)
* Accessor functions replacing the "weak" functions in
* drivers/net/smc911x.c
*/
u32 smc911x_reg_read(u32 addr)
u32 smc911x_reg_read(struct eth_device *dev, u32 addr)
{
volatile u32 data;
addr += dev->iobase;
reg_write(EBI_DEV1_CONFIG2(EBI_BASE), 0x0000004F);
ebi_wait();
reg_write(EBI_CPU_IO_ACCS(EBI_BASE), (EXT_DEVICE_CHANNEL_1 | addr));
@ -58,8 +60,9 @@ u32 smc911x_reg_read(u32 addr)
return (data);
}
void smc911x_reg_write(u32 addr, u32 data)
void smc911x_reg_write(struct eth_device *dev, u32 addr, u32 data)
{
addr += dev->iobase;
reg_write(EBI_DEV1_CONFIG2(EBI_BASE), 0x0000004F);
ebi_wait();
reg_write(EBI_IO_ACCS_DATA(EBI_BASE), data);
@ -68,8 +71,9 @@ void smc911x_reg_write(u32 addr, u32 data)
ebi_wait();
}
void pkt_data_push(u32 addr, u32 data)
void pkt_data_push(struct eth_device *dev, u32 addr, u32 data)
{
addr += dev->iobase;
reg_write(EBI_DEV1_CONFIG2(EBI_BASE), 0x0000004A);
ebi_wait();
reg_write(EBI_IO_ACCS_DATA(EBI_BASE), data);
@ -80,10 +84,11 @@ void pkt_data_push(u32 addr, u32 data)
return;
}
u32 pkt_data_pull(u32 addr)
u32 pkt_data_pull(struct eth_device *dev, u32 addr)
{
volatile u32 data;
addr += dev->iobase;
reg_write(EBI_DEV1_CONFIG2(EBI_BASE), 0x0000004A);
ebi_wait();
reg_write(EBI_CPU_IO_ACCS(EBI_BASE), (EXT_DEVICE_CHANNEL_1 | addr));
@ -92,3 +97,12 @@ u32 pkt_data_pull(u32 addr)
return data;
}
int board_eth_init(bd_t *bis)
{
int rc = 0;
#ifdef CONFIG_SMC911X
rc = smc911x_initialize(0, CONFIG_DRIVER_SMC911X_BASE);
#endif
return rc;
}

View file

@ -21,6 +21,7 @@
#include <common.h>
#include <command.h>
#include <netdev.h>
#include <asm/mipsregs.h>
#include "vct.h"
@ -115,3 +116,12 @@ int checkboard(void)
return 0;
}
int board_eth_init(bd_t *bis)
{
int rc = 0;
#ifdef CONFIG_SMC911X
rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
#endif
return rc;
}

View file

@ -28,6 +28,7 @@
* MA 02111-1307 USA
*/
#include <common.h>
#include <netdev.h>
#include <asm/io.h>
#include <asm/arch/mem.h>
#include <asm/arch/mux.h>
@ -122,3 +123,12 @@ static void setup_net_chip(void)
udelay(1);
writel(GPIO0, &gpio3_base->setdataout);
}
int board_eth_init(bd_t *bis)
{
int rc = 0;
#ifdef CONFIG_SMC911X
rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
#endif
return rc;
}

View file

@ -19,6 +19,7 @@
*/
#include <common.h>
#include <netdev.h>
#include <asm/io.h>
#include <asm/processor.h>
@ -160,3 +161,12 @@ void ide_set_reset(int idereset)
udelay(FPGA_NAND_RST_WAIT);
outw(FPGA_NAND_INIT, FPGA_NAND_CTL);
}
int board_eth_init(bd_t *bis)
{
int rc = 0;
#ifdef CONFIG_SMC911X
rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
#endif
return rc;
}

View file

@ -21,6 +21,7 @@
*/
#include <common.h>
#include <netdev.h>
#include <asm/io.h>
#include <asm/processor.h>
@ -57,15 +58,25 @@ void led_set_state(unsigned short value)
* And this has problem by FIFO access only. pkt_data_pull/pkt_data_push
* functions necessary to solve this problem.
*/
u32 pkt_data_pull(u32 addr)
u32 pkt_data_pull(struct eth_device *dev, u32 addr)
{
volatile u16 *addr_16 = (u16 *)addr;
volatile u16 *addr_16 = (u16 *)(dev->iobase + addr);
return (u32)((swab16(*addr_16) << 16) & 0xFFFF0000)\
| swab16(*(addr_16 + 1));
}
void pkt_data_push(u32 addr, u32 val)
void pkt_data_push(struct eth_device *dev, u32 addr, u32 val)
{
addr += dev->iobase;
*(volatile u16 *)(addr + 2) = swab16((u16)val);
*(volatile u16 *)(addr) = swab16((u16)(val >> 16));
}
int board_eth_init(bd_t *bis)
{
int rc = 0;
#ifdef CONFIG_SMC911X
rc = smc911x_initialize(0, CONFIG_SMC911X_BASE);
#endif
return rc;
}

View file

@ -353,3 +353,52 @@ U_BOOT_CMD(
"[NTP server IP]\n"
);
#endif
#if defined(CONFIG_CMD_DNS)
int do_dns(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
if (argc == 1) {
cmd_usage(cmdtp);
return -1;
}
/*
* We should check for a valid hostname:
* - Each label must be between 1 and 63 characters long
* - the entire hostname has a maximum of 255 characters
* - only the ASCII letters 'a' through 'z' (case-insensitive),
* the digits '0' through '9', and the hyphen
* - cannot begin or end with a hyphen
* - no other symbols, punctuation characters, or blank spaces are
* permitted
* but hey - this is a minimalist implmentation, so only check length
* and let the name server deal with things.
*/
if (strlen(argv[1]) >= 255) {
printf("dns error: hostname too long\n");
return 1;
}
NetDNSResolve = argv[1];
if (argc == 3)
NetDNSenvvar = argv[2];
else
NetDNSenvvar = NULL;
if (NetLoop(DNS) < 0) {
printf("dns lookup of %s failed, check setup\n", argv[1]);
return 1;
}
return 0;
}
U_BOOT_CMD(
dns, 3, 1, do_dns,
"lookup the IP of a hostname",
"hostname [envvar]"
);
#endif /* CONFIG_CMD_DNS */

View file

@ -24,6 +24,7 @@
#include <at91rm9200_net.h>
#include <net.h>
#include <miiphy.h>
#include <asm/mach-types.h>
/* ----- Ethernet Buffer definitions ----- */
@ -184,7 +185,7 @@ int eth_init (bd_t * bd)
p_mac->EMAC_CFG |= AT91C_EMAC_CSR; /* Clear statistics */
/* Init Ehternet buffers */
/* Init Ethernet buffers */
for (i = 0; i < RBF_FRAMEMAX; i++) {
rbfdt[i].addr = (unsigned long)rbf_framebuf[i];
rbfdt[i].size = 0;
@ -193,9 +194,22 @@ int eth_init (bd_t * bd)
rbfp = &rbfdt[0];
eth_getenv_enetaddr("ethaddr", enetaddr);
p_mac->EMAC_SA2L = (enetaddr[3] << 24) | (enetaddr[2] << 16)
| (enetaddr[1] << 8) | (enetaddr[0]);
p_mac->EMAC_SA2H = (enetaddr[5] << 8) | (enetaddr[4]);
/* The CSB337 originally used a version of the MicroMonitor bootloader
* which saved Ethernet addresses in the "wrong" order. Operating
* systems (like Linux) know this, and apply a workaround. Replicate
* that MicroMonitor behavior so we avoid needing to make such OS code
* care about which bootloader was used.
*/
if (machine_is_csb337()) {
p_mac->EMAC_SA2H = (enetaddr[0] << 8) | (enetaddr[1]);
p_mac->EMAC_SA2L = (enetaddr[2] << 24) | (enetaddr[3] << 16)
| (enetaddr[4] << 8) | (enetaddr[5]);
} else {
p_mac->EMAC_SA2L = (enetaddr[3] << 24) | (enetaddr[2] << 16)
| (enetaddr[1] << 8) | (enetaddr[0]);
p_mac->EMAC_SA2H = (enetaddr[5] << 8) | (enetaddr[4]);
}
p_mac->EMAC_RBQP = (long) (&rbfdt[0]);
p_mac->EMAC_RSR &= ~(AT91C_EMAC_RSR_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA);

View file

@ -20,6 +20,7 @@
#include <common.h>
#include <div64.h>
#include <netdev.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
@ -159,6 +160,15 @@ int print_cpuinfo (void)
}
#endif
int cpu_eth_init(bd_t *bis)
{
#if defined(CONFIG_FEC_MXC)
return fecmxc_initialize(bis);
#else
return 0;
#endif
}
void imx_gpio_mode(int gpio_mode)
{
struct gpio_regs *regs = (struct gpio_regs *)IMX_GPIO_BASE;

64
doc/README.dns Normal file
View file

@ -0,0 +1,64 @@
Domain Name System
-------------------------------------------
The Domain Name System (DNS) is a hierarchical naming system for computers,
services, or any resource participating in the Internet. It associates various
information with domain names assigned to each of the participants. Most
importantly, it translates domain names meaningful to humans into the numerical
(binary) identifiers associated with networking equipment for the purpose of
locating and addressing these devices world-wide. An often used analogy to
explain the Domain Name System is that it serves as the "phone book" for the
Internet by translating human-friendly computer hostnames into IP addresses.
For example, www.example.com translates to 208.77.188.166.
For more information on DNS - http://en.wikipedia.org/wiki/Domain_Name_System
U-Boot and DNS
------------------------------------------
CONFIG_CMD_DNS - controls if the 'dns' command is compiled in. If it is, it
will send name lookups to the dns server (env var 'dnsip')
Turning this option on will about abou 1k to U-Boot's size.
Example:
bfin> print dnsip
dnsip=192.168.0.1
bfin> dns www.google.com
66.102.1.104
By default, dns does nothing except print the IP number on
the default console - which by itself, would be pretty
useless. Adding a third argument to the dns command will
use that as the environment variable to be set.
Example:
bfin> print googleip
## Error: "googleip" not defined
bfin> dns www.google.com googleip
64.233.161.104
bfin> print googleip
googleip=64.233.161.104
bfin> ping ${googleip}
Using Blackfin EMAC device
host 64.233.161.104 is alive
In this way, you can lookup, and set many more meaningful
things.
bfin> sntp
ntpserverip not set
bfin> dns pool.ntp.org ntpserverip
72.18.205.156
bfin> sntp
Date: 2009-07-18 Time: 4:06:57
For some helpful things that can be related to DNS in U-Boot,
look at the top level README for these config options:
CONFIG_CMD_DHCP
CONFIG_BOOTP_DNS
CONFIG_BOOTP_DNS2

View file

@ -870,7 +870,7 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
defined(CONFIG_405EX)
u32 opbfreq;
sys_info_t sysinfo;
#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
#if defined(CONFIG_440GX) || \
defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
defined(CONFIG_405EX)
@ -1119,7 +1119,6 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis)
#if defined(CONFIG_440GX) || \
defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \
defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
defined(CONFIG_405EX)

View file

@ -37,6 +37,7 @@ COBJS-$(CONFIG_DNET) += dnet.o
COBJS-$(CONFIG_E1000) += e1000.o
COBJS-$(CONFIG_EEPRO100) += eepro100.o
COBJS-$(CONFIG_ENC28J60) += enc28j60.o
COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o
COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o
COBJS-$(CONFIG_GRETH) += greth.o
COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o
@ -63,7 +64,7 @@ COBJS-$(CONFIG_RTL8169) += rtl8169.o
COBJS-$(CONFIG_DRIVER_S3C4510_ETH) += s3c4510b_eth.o
COBJS-$(CONFIG_SH_ETHER) += sh_eth.o
COBJS-$(CONFIG_DRIVER_SMC91111) += smc91111.o
COBJS-$(CONFIG_DRIVER_SMC911X) += smc911x.o
COBJS-$(CONFIG_SMC911X) += smc911x.o
COBJS-$(CONFIG_TIGON3) += tigon3.o bcm570x_autoneg.o 5701rls.o
COBJS-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o
COBJS-$(CONFIG_TSEC_ENET) += tsec.o

742
drivers/net/fec_mxc.c Normal file
View file

@ -0,0 +1,742 @@
/*
* (C) Copyright 2009 Ilya Yanok, Emcraft Systems Ltd <yanok@emcraft.com>
* (C) Copyright 2008,2009 Eric Jarrige <eric.jarrige@armadeus.org>
* (C) Copyright 2008 Armadeus Systems nc
* (C) Copyright 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
* (C) Copyright 2007 Pengutronix, Juergen Beisert <j.beisert@pengutronix.de>
*
* 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.
*
* 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
*/
#include <common.h>
#include <malloc.h>
#include <net.h>
#include <miiphy.h>
#include "fec_mxc.h"
#include <asm/arch/clock.h>
#include <asm/arch/imx-regs.h>
#include <asm/io.h>
#include <asm/errno.h>
DECLARE_GLOBAL_DATA_PTR;
#ifndef CONFIG_MII
#error "CONFIG_MII has to be defined!"
#endif
#undef DEBUG
struct nbuf {
uint8_t data[1500]; /**< actual data */
int length; /**< actual length */
int used; /**< buffer in use or not */
uint8_t head[16]; /**< MAC header(6 + 6 + 2) + 2(aligned) */
};
struct fec_priv gfec = {
.eth = (struct ethernet_regs *)IMX_FEC_BASE,
.xcv_type = MII100,
.rbd_base = NULL,
.rbd_index = 0,
.tbd_base = NULL,
.tbd_index = 0,
.bd = NULL,
};
/*
* MII-interface related functions
*/
static int fec_miiphy_read(char *dev, uint8_t phyAddr, uint8_t regAddr,
uint16_t *retVal)
{
struct eth_device *edev = eth_get_dev_by_name(dev);
struct fec_priv *fec = (struct fec_priv *)edev->priv;
uint32_t reg; /* convenient holder for the PHY register */
uint32_t phy; /* convenient holder for the PHY */
uint32_t start;
/*
* reading from any PHY's register is done by properly
* programming the FEC's MII data register.
*/
writel(FEC_IEVENT_MII, &fec->eth->ievent);
reg = regAddr << FEC_MII_DATA_RA_SHIFT;
phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
writel(FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA |
phy | reg, &fec->eth->mii_data);
/*
* wait for the related interrupt
*/
start = get_timer_masked();
while (!(readl(&fec->eth->ievent) & FEC_IEVENT_MII)) {
if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
printf("Read MDIO failed...\n");
return -1;
}
}
/*
* clear mii interrupt bit
*/
writel(FEC_IEVENT_MII, &fec->eth->ievent);
/*
* it's now safe to read the PHY's register
*/
*retVal = readl(&fec->eth->mii_data);
debug("fec_miiphy_read: phy: %02x reg:%02x val:%#x\n", phyAddr,
regAddr, *retVal);
return 0;
}
static int fec_miiphy_write(char *dev, uint8_t phyAddr, uint8_t regAddr,
uint16_t data)
{
struct eth_device *edev = eth_get_dev_by_name(dev);
struct fec_priv *fec = (struct fec_priv *)edev->priv;
uint32_t reg; /* convenient holder for the PHY register */
uint32_t phy; /* convenient holder for the PHY */
uint32_t start;
reg = regAddr << FEC_MII_DATA_RA_SHIFT;
phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
writel(FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR |
FEC_MII_DATA_TA | phy | reg | data, &fec->eth->mii_data);
/*
* wait for the MII interrupt
*/
start = get_timer_masked();
while (!(readl(&fec->eth->ievent) & FEC_IEVENT_MII)) {
if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) {
printf("Write MDIO failed...\n");
return -1;
}
}
/*
* clear MII interrupt bit
*/
writel(FEC_IEVENT_MII, &fec->eth->ievent);
debug("fec_miiphy_write: phy: %02x reg:%02x val:%#x\n", phyAddr,
regAddr, data);
return 0;
}
static int miiphy_restart_aneg(struct eth_device *dev)
{
/*
* Wake up from sleep if necessary
* Reset PHY, then delay 300ns
*/
miiphy_write(dev->name, CONFIG_FEC_MXC_PHYADDR, PHY_MIPGSR, 0x00FF);
miiphy_write(dev->name, CONFIG_FEC_MXC_PHYADDR, PHY_BMCR,
PHY_BMCR_RESET);
udelay(1000);
/*
* Set the auto-negotiation advertisement register bits
*/
miiphy_write(dev->name, CONFIG_FEC_MXC_PHYADDR, PHY_ANAR, 0x1e0);
miiphy_write(dev->name, CONFIG_FEC_MXC_PHYADDR, PHY_BMCR,
PHY_BMCR_AUTON | PHY_BMCR_RST_NEG);
return 0;
}
static int miiphy_wait_aneg(struct eth_device *dev)
{
uint32_t start;
uint16_t status;
/*
* Wait for AN completion
*/
start = get_timer_masked();
do {
if (get_timer(start) > (CONFIG_SYS_HZ * 5)) {
printf("%s: Autonegotiation timeout\n", dev->name);
return -1;
}
if (miiphy_read(dev->name, CONFIG_FEC_MXC_PHYADDR,
PHY_BMSR, &status)) {
printf("%s: Autonegotiation failed. status: 0x%04x\n",
dev->name, status);
return -1;
}
} while (!(status & PHY_BMSR_LS));
return 0;
}
static int fec_rx_task_enable(struct fec_priv *fec)
{
writel(1 << 24, &fec->eth->r_des_active);
return 0;
}
static int fec_rx_task_disable(struct fec_priv *fec)
{
return 0;
}
static int fec_tx_task_enable(struct fec_priv *fec)
{
writel(1 << 24, &fec->eth->x_des_active);
return 0;
}
static int fec_tx_task_disable(struct fec_priv *fec)
{
return 0;
}
/**
* Initialize receive task's buffer descriptors
* @param[in] fec all we know about the device yet
* @param[in] count receive buffer count to be allocated
* @param[in] size size of each receive buffer
* @return 0 on success
*
* For this task we need additional memory for the data buffers. And each
* data buffer requires some alignment. Thy must be aligned to a specific
* boundary each (DB_DATA_ALIGNMENT).
*/
static int fec_rbd_init(struct fec_priv *fec, int count, int size)
{
int ix;
uint32_t p = 0;
/* reserve data memory and consider alignment */
fec->rdb_ptr = malloc(size * count + DB_DATA_ALIGNMENT);
p = (uint32_t)fec->rdb_ptr;
if (!p) {
puts("fec_imx27: not enough malloc memory!\n");
return -ENOMEM;
}
memset((void *)p, 0, size * count + DB_DATA_ALIGNMENT);
p += DB_DATA_ALIGNMENT-1;
p &= ~(DB_DATA_ALIGNMENT-1);
for (ix = 0; ix < count; ix++) {
writel(p, &fec->rbd_base[ix].data_pointer);
p += size;
writew(FEC_RBD_EMPTY, &fec->rbd_base[ix].status);
writew(0, &fec->rbd_base[ix].data_length);
}
/*
* mark the last RBD to close the ring
*/
writew(FEC_RBD_WRAP | FEC_RBD_EMPTY, &fec->rbd_base[ix - 1].status);
fec->rbd_index = 0;
return 0;
}
/**
* Initialize transmit task's buffer descriptors
* @param[in] fec all we know about the device yet
*
* Transmit buffers are created externally. We only have to init the BDs here.\n
* Note: There is a race condition in the hardware. When only one BD is in
* use it must be marked with the WRAP bit to use it for every transmitt.
* This bit in combination with the READY bit results into double transmit
* of each data buffer. It seems the state machine checks READY earlier then
* resetting it after the first transfer.
* Using two BDs solves this issue.
*/
static void fec_tbd_init(struct fec_priv *fec)
{
writew(0x0000, &fec->tbd_base[0].status);
writew(FEC_TBD_WRAP, &fec->tbd_base[1].status);
fec->tbd_index = 0;
}
/**
* Mark the given read buffer descriptor as free
* @param[in] last 1 if this is the last buffer descriptor in the chain, else 0
* @param[in] pRbd buffer descriptor to mark free again
*/
static void fec_rbd_clean(int last, struct fec_bd *pRbd)
{
/*
* Reset buffer descriptor as empty
*/
if (last)
writew(FEC_RBD_WRAP | FEC_RBD_EMPTY, &pRbd->status);
else
writew(FEC_RBD_EMPTY, &pRbd->status);
/*
* no data in it
*/
writew(0, &pRbd->data_length);
}
static int fec_get_hwaddr(struct eth_device *dev, unsigned char *mac)
{
struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE;
int i;
for (i = 0; i < 6; i++)
mac[6-1-i] = readl(&iim->iim_bank_area0[IIM0_MAC + i]);
return is_valid_ether_addr(mac);
}
static int fec_set_hwaddr(struct eth_device *dev, unsigned char *mac)
{
struct fec_priv *fec = (struct fec_priv *)dev->priv;
writel(0, &fec->eth->iaddr1);
writel(0, &fec->eth->iaddr2);
writel(0, &fec->eth->gaddr1);
writel(0, &fec->eth->gaddr2);
/*
* Set physical address
*/
writel((mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3],
&fec->eth->paddr1);
writel((mac[4] << 24) + (mac[5] << 16) + 0x8808, &fec->eth->paddr2);
return 0;
}
/**
* Start the FEC engine
* @param[in] dev Our device to handle
*/
static int fec_open(struct eth_device *edev)
{
struct fec_priv *fec = (struct fec_priv *)edev->priv;
debug("fec_open: fec_open(dev)\n");
/* full-duplex, heartbeat disabled */
writel(1 << 2, &fec->eth->x_cntrl);
fec->rbd_index = 0;
/*
* Enable FEC-Lite controller
*/
writel(FEC_ECNTRL_ETHER_EN, &fec->eth->ecntrl);
miiphy_wait_aneg(edev);
miiphy_speed(edev->name, 0);
miiphy_duplex(edev->name, 0);
/*
* Enable SmartDMA receive task
*/
fec_rx_task_enable(fec);
udelay(100000);
return 0;
}
static int fec_init(struct eth_device *dev, bd_t* bd)
{
uint32_t base;
struct fec_priv *fec = (struct fec_priv *)dev->priv;
/*
* reserve memory for both buffer descriptor chains at once
* Datasheet forces the startaddress of each chain is 16 byte
* aligned
*/
fec->base_ptr = malloc((2 + FEC_RBD_NUM) *
sizeof(struct fec_bd) + DB_ALIGNMENT);
base = (uint32_t)fec->base_ptr;
if (!base) {
puts("fec_imx27: not enough malloc memory!\n");
return -ENOMEM;
}
memset((void *)base, 0, (2 + FEC_RBD_NUM) *
sizeof(struct fec_bd) + DB_ALIGNMENT);
base += (DB_ALIGNMENT-1);
base &= ~(DB_ALIGNMENT-1);
fec->rbd_base = (struct fec_bd *)base;
base += FEC_RBD_NUM * sizeof(struct fec_bd);
fec->tbd_base = (struct fec_bd *)base;
/*
* Set interrupt mask register
*/
writel(0x00000000, &fec->eth->imask);
/*
* Clear FEC-Lite interrupt event register(IEVENT)
*/
writel(0xffffffff, &fec->eth->ievent);
/*
* Set FEC-Lite receive control register(R_CNTRL):
*/
if (fec->xcv_type == SEVENWIRE) {
/*
* Frame length=1518; 7-wire mode
*/
writel(0x05ee0020, &fec->eth->r_cntrl); /* FIXME 0x05ee0000 */
} else {
/*
* Frame length=1518; MII mode;
*/
writel(0x05ee0024, &fec->eth->r_cntrl); /* FIXME 0x05ee0004 */
/*
* Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
* and do not drop the Preamble.
*/
writel((((imx_get_ahbclk() / 1000000) + 2) / 5) << 1,
&fec->eth->mii_speed);
debug("fec_init: mii_speed %#lx\n",
(((imx_get_ahbclk() / 1000000) + 2) / 5) << 1);
}
/*
* Set Opcode/Pause Duration Register
*/
writel(0x00010020, &fec->eth->op_pause); /* FIXME 0xffff0020; */
writel(0x2, &fec->eth->x_wmrk);
/*
* Set multicast address filter
*/
writel(0x00000000, &fec->eth->gaddr1);
writel(0x00000000, &fec->eth->gaddr2);
/* clear MIB RAM */
long *mib_ptr = (long *)(IMX_FEC_BASE + 0x200);
while (mib_ptr <= (long *)(IMX_FEC_BASE + 0x2FC))
*mib_ptr++ = 0;
/* FIFO receive start register */
writel(0x520, &fec->eth->r_fstart);
/* size and address of each buffer */
writel(FEC_MAX_PKT_SIZE, &fec->eth->emrbr);
writel((uint32_t)fec->tbd_base, &fec->eth->etdsr);
writel((uint32_t)fec->rbd_base, &fec->eth->erdsr);
/*
* Initialize RxBD/TxBD rings
*/
if (fec_rbd_init(fec, FEC_RBD_NUM, FEC_MAX_PKT_SIZE) < 0) {
free(fec->base_ptr);
return -ENOMEM;
}
fec_tbd_init(fec);
if (fec->xcv_type != SEVENWIRE)
miiphy_restart_aneg(dev);
fec_open(dev);
return 0;
}
/**
* Halt the FEC engine
* @param[in] dev Our device to handle
*/
static void fec_halt(struct eth_device *dev)
{
struct fec_priv *fec = &gfec;
int counter = 0xffff;
/*
* issue graceful stop command to the FEC transmitter if necessary
*/
writel(FEC_ECNTRL_RESET | readl(&fec->eth->x_cntrl),
&fec->eth->x_cntrl);
debug("eth_halt: wait for stop regs\n");
/*
* wait for graceful stop to register
*/
while ((counter--) && (!(readl(&fec->eth->ievent) & FEC_IEVENT_GRA)))
; /* FIXME ensure time */
/*
* Disable SmartDMA tasks
*/
fec_tx_task_disable(fec);
fec_rx_task_disable(fec);
/*
* Disable the Ethernet Controller
* Note: this will also reset the BD index counter!
*/
writel(0, &fec->eth->ecntrl);
fec->rbd_index = 0;
fec->tbd_index = 0;
free(fec->rdb_ptr);
free(fec->base_ptr);
debug("eth_halt: done\n");
}
/**
* Transmit one frame
* @param[in] dev Our ethernet device to handle
* @param[in] packet Pointer to the data to be transmitted
* @param[in] length Data count in bytes
* @return 0 on success
*/
static int fec_send(struct eth_device *dev, volatile void* packet, int length)
{
unsigned int status;
/*
* This routine transmits one frame. This routine only accepts
* 6-byte Ethernet addresses.
*/
struct fec_priv *fec = (struct fec_priv *)dev->priv;
/*
* Check for valid length of data.
*/
if ((length > 1500) || (length <= 0)) {
printf("Payload (%d) to large!\n", length);
return -1;
}
/*
* Setup the transmit buffer
* Note: We are always using the first buffer for transmission,
* the second will be empty and only used to stop the DMA engine
*/
writew(length, &fec->tbd_base[fec->tbd_index].data_length);
writel((uint32_t)packet, &fec->tbd_base[fec->tbd_index].data_pointer);
/*
* update BD's status now
* This block:
* - is always the last in a chain (means no chain)
* - should transmitt the CRC
* - might be the last BD in the list, so the address counter should
* wrap (-> keep the WRAP flag)
*/
status = readw(&fec->tbd_base[fec->tbd_index].status) & FEC_TBD_WRAP;
status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY;
writew(status, &fec->tbd_base[fec->tbd_index].status);
/*
* Enable SmartDMA transmit task
*/
fec_tx_task_enable(fec);
/*
* wait until frame is sent .
*/
while (readw(&fec->tbd_base[fec->tbd_index].status) & FEC_TBD_READY) {
/* FIXME: Timeout */
}
debug("fec_send: status 0x%x index %d\n",
readw(&fec->tbd_base[fec->tbd_index].status),
fec->tbd_index);
/* for next transmission use the other buffer */
if (fec->tbd_index)
fec->tbd_index = 0;
else
fec->tbd_index = 1;
return 0;
}
/**
* Pull one frame from the card
* @param[in] dev Our ethernet device to handle
* @return Length of packet read
*/
static int fec_recv(struct eth_device *dev)
{
struct fec_priv *fec = (struct fec_priv *)dev->priv;
struct fec_bd *rbd = &fec->rbd_base[fec->rbd_index];
unsigned long ievent;
int frame_length, len = 0;
struct nbuf *frame;
uint16_t bd_status;
uchar buff[FEC_MAX_PKT_SIZE];
/*
* Check if any critical events have happened
*/
ievent = readl(&fec->eth->ievent);
writel(ievent, &fec->eth->ievent);
debug("fec_recv: ievent 0x%x\n", ievent);
if (ievent & FEC_IEVENT_BABR) {
fec_halt(dev);
fec_init(dev, fec->bd);
printf("some error: 0x%08lx\n", ievent);
return 0;
}
if (ievent & FEC_IEVENT_HBERR) {
/* Heartbeat error */
writel(0x00000001 | readl(&fec->eth->x_cntrl),
&fec->eth->x_cntrl);
}
if (ievent & FEC_IEVENT_GRA) {
/* Graceful stop complete */
if (readl(&fec->eth->x_cntrl) & 0x00000001) {
fec_halt(dev);
writel(~0x00000001 & readl(&fec->eth->x_cntrl),
&fec->eth->x_cntrl);
fec_init(dev, fec->bd);
}
}
/*
* ensure reading the right buffer status
*/
bd_status = readw(&rbd->status);
debug("fec_recv: status 0x%x\n", bd_status);
if (!(bd_status & FEC_RBD_EMPTY)) {
if ((bd_status & FEC_RBD_LAST) && !(bd_status & FEC_RBD_ERR) &&
((readw(&rbd->data_length) - 4) > 14)) {
/*
* Get buffer address and size
*/
frame = (struct nbuf *)readl(&rbd->data_pointer);
frame_length = readw(&rbd->data_length) - 4;
/*
* Fill the buffer and pass it to upper layers
*/
memcpy(buff, frame->data, frame_length);
NetReceive(buff, frame_length);
len = frame_length;
} else {
if (bd_status & FEC_RBD_ERR)
printf("error frame: 0x%08lx 0x%08x\n",
(ulong)rbd->data_pointer,
bd_status);
}
/*
* free the current buffer, restart the engine
* and move forward to the next buffer
*/
fec_rbd_clean(fec->rbd_index == (FEC_RBD_NUM - 1) ? 1 : 0, rbd);
fec_rx_task_enable(fec);
fec->rbd_index = (fec->rbd_index + 1) % FEC_RBD_NUM;
}
debug("fec_recv: stop\n");
return len;
}
static int fec_probe(bd_t *bd)
{
struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
struct eth_device *edev;
struct fec_priv *fec = &gfec;
unsigned char ethaddr_str[20];
unsigned char ethaddr[6];
char *tmp = getenv("ethaddr");
char *end;
/* enable FEC clock */
writel(readl(&pll->pccr1) | PCCR1_HCLK_FEC, &pll->pccr1);
writel(readl(&pll->pccr0) | PCCR0_FEC_EN, &pll->pccr0);
/* create and fill edev struct */
edev = (struct eth_device *)malloc(sizeof(struct eth_device));
if (!edev) {
puts("fec_imx27: not enough malloc memory!\n");
return -ENOMEM;
}
edev->priv = fec;
edev->init = fec_init;
edev->send = fec_send;
edev->recv = fec_recv;
edev->halt = fec_halt;
fec->eth = (struct ethernet_regs *)IMX_FEC_BASE;
fec->bd = bd;
fec->xcv_type = MII100;
/* Reset chip. */
writel(FEC_ECNTRL_RESET, &fec->eth->ecntrl);
while (readl(&fec->eth->ecntrl) & 1)
udelay(10);
/*
* Set interrupt mask register
*/
writel(0x00000000, &fec->eth->imask);
/*
* Clear FEC-Lite interrupt event register(IEVENT)
*/
writel(0xffffffff, &fec->eth->ievent);
/*
* Set FEC-Lite receive control register(R_CNTRL):
*/
/*
* Frame length=1518; MII mode;
*/
writel(0x05ee0024, &fec->eth->r_cntrl); /* FIXME 0x05ee0004 */
/*
* Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
* and do not drop the Preamble.
*/
writel((((imx_get_ahbclk() / 1000000) + 2) / 5) << 1,
&fec->eth->mii_speed);
debug("fec_init: mii_speed %#lx\n",
(((imx_get_ahbclk() / 1000000) + 2) / 5) << 1);
sprintf(edev->name, "FEC_MXC");
miiphy_register(edev->name, fec_miiphy_read, fec_miiphy_write);
eth_register(edev);
if ((NULL != tmp) && (12 <= strlen(tmp))) {
int i;
/* convert MAC from string to int */
for (i = 0; i < 6; i++) {
ethaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
if (tmp)
tmp = (*end) ? end + 1 : end;
}
} else if (fec_get_hwaddr(edev, ethaddr) == 0) {
printf("got MAC address from EEPROM: %pM\n", ethaddr);
setenv("ethaddr", (char *)ethaddr_str);
}
memcpy(edev->enetaddr, ethaddr, 6);
fec_set_hwaddr(edev, ethaddr);
return 0;
}
int fecmxc_initialize(bd_t *bd)
{
int lout = 1;
debug("eth_init: fec_probe(bd)\n");
lout = fec_probe(bd);
return lout;
}

304
drivers/net/fec_mxc.h Normal file
View file

@ -0,0 +1,304 @@
/*
* (C) Copyright 2009 Ilya Yanok, Emcraft Systems Ltd <yanok@emcraft.com>
* (C) Copyright 2008 Armadeus Systems, nc
* (C) Copyright 2008 Eric Jarrige <eric.jarrige@armadeus.org>
* (C) Copyright 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
* (C) Copyright 2007 Pengutronix, Juergen Beisert <j.beisert@pengutronix.de>
*
* (C) Copyright 2003
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* This file is based on mpc4200fec.h
* (C) Copyright Motorola, Inc., 2000
*
* 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.
*
* 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 __FEC_MXC_H
#define __FEC_MXC_H
/**
* Layout description of the FEC
*/
struct ethernet_regs {
/* [10:2]addr = 00 */
/* Control and status Registers (offset 000-1FF) */
uint32_t res0[1]; /* MBAR_ETH + 0x000 */
uint32_t ievent; /* MBAR_ETH + 0x004 */
uint32_t imask; /* MBAR_ETH + 0x008 */
uint32_t res1[1]; /* MBAR_ETH + 0x00C */
uint32_t r_des_active; /* MBAR_ETH + 0x010 */
uint32_t x_des_active; /* MBAR_ETH + 0x014 */
uint32_t res2[3]; /* MBAR_ETH + 0x018-20 */
uint32_t ecntrl; /* MBAR_ETH + 0x024 */
uint32_t res3[6]; /* MBAR_ETH + 0x028-03C */
uint32_t mii_data; /* MBAR_ETH + 0x040 */
uint32_t mii_speed; /* MBAR_ETH + 0x044 */
uint32_t res4[7]; /* MBAR_ETH + 0x048-60 */
uint32_t mib_control; /* MBAR_ETH + 0x064 */
uint32_t res5[7]; /* MBAR_ETH + 0x068-80 */
uint32_t r_cntrl; /* MBAR_ETH + 0x084 */
uint32_t res6[15]; /* MBAR_ETH + 0x088-C0 */
uint32_t x_cntrl; /* MBAR_ETH + 0x0C4 */
uint32_t res7[7]; /* MBAR_ETH + 0x0C8-E0 */
uint32_t paddr1; /* MBAR_ETH + 0x0E4 */
uint32_t paddr2; /* MBAR_ETH + 0x0E8 */
uint32_t op_pause; /* MBAR_ETH + 0x0EC */
uint32_t res8[10]; /* MBAR_ETH + 0x0F0-114 */
uint32_t iaddr1; /* MBAR_ETH + 0x118 */
uint32_t iaddr2; /* MBAR_ETH + 0x11C */
uint32_t gaddr1; /* MBAR_ETH + 0x120 */
uint32_t gaddr2; /* MBAR_ETH + 0x124 */
uint32_t res9[7]; /* MBAR_ETH + 0x128-140 */
uint32_t x_wmrk; /* MBAR_ETH + 0x144 */
uint32_t res10[1]; /* MBAR_ETH + 0x148 */
uint32_t r_bound; /* MBAR_ETH + 0x14C */
uint32_t r_fstart; /* MBAR_ETH + 0x150 */
uint32_t res11[11]; /* MBAR_ETH + 0x154-17C */
uint32_t erdsr; /* MBAR_ETH + 0x180 */
uint32_t etdsr; /* MBAR_ETH + 0x184 */
uint32_t emrbr; /* MBAR_ETH + 0x188 */
uint32_t res12[29]; /* MBAR_ETH + 0x18C-1FC */
/* MIB COUNTERS (Offset 200-2FF) */
uint32_t rmon_t_drop; /* MBAR_ETH + 0x200 */
uint32_t rmon_t_packets; /* MBAR_ETH + 0x204 */
uint32_t rmon_t_bc_pkt; /* MBAR_ETH + 0x208 */
uint32_t rmon_t_mc_pkt; /* MBAR_ETH + 0x20C */
uint32_t rmon_t_crc_align; /* MBAR_ETH + 0x210 */
uint32_t rmon_t_undersize; /* MBAR_ETH + 0x214 */
uint32_t rmon_t_oversize; /* MBAR_ETH + 0x218 */
uint32_t rmon_t_frag; /* MBAR_ETH + 0x21C */
uint32_t rmon_t_jab; /* MBAR_ETH + 0x220 */
uint32_t rmon_t_col; /* MBAR_ETH + 0x224 */
uint32_t rmon_t_p64; /* MBAR_ETH + 0x228 */
uint32_t rmon_t_p65to127; /* MBAR_ETH + 0x22C */
uint32_t rmon_t_p128to255; /* MBAR_ETH + 0x230 */
uint32_t rmon_t_p256to511; /* MBAR_ETH + 0x234 */
uint32_t rmon_t_p512to1023; /* MBAR_ETH + 0x238 */
uint32_t rmon_t_p1024to2047; /* MBAR_ETH + 0x23C */
uint32_t rmon_t_p_gte2048; /* MBAR_ETH + 0x240 */
uint32_t rmon_t_octets; /* MBAR_ETH + 0x244 */
uint32_t ieee_t_drop; /* MBAR_ETH + 0x248 */
uint32_t ieee_t_frame_ok; /* MBAR_ETH + 0x24C */
uint32_t ieee_t_1col; /* MBAR_ETH + 0x250 */
uint32_t ieee_t_mcol; /* MBAR_ETH + 0x254 */
uint32_t ieee_t_def; /* MBAR_ETH + 0x258 */
uint32_t ieee_t_lcol; /* MBAR_ETH + 0x25C */
uint32_t ieee_t_excol; /* MBAR_ETH + 0x260 */
uint32_t ieee_t_macerr; /* MBAR_ETH + 0x264 */
uint32_t ieee_t_cserr; /* MBAR_ETH + 0x268 */
uint32_t ieee_t_sqe; /* MBAR_ETH + 0x26C */
uint32_t t_fdxfc; /* MBAR_ETH + 0x270 */
uint32_t ieee_t_octets_ok; /* MBAR_ETH + 0x274 */
uint32_t res13[2]; /* MBAR_ETH + 0x278-27C */
uint32_t rmon_r_drop; /* MBAR_ETH + 0x280 */
uint32_t rmon_r_packets; /* MBAR_ETH + 0x284 */
uint32_t rmon_r_bc_pkt; /* MBAR_ETH + 0x288 */
uint32_t rmon_r_mc_pkt; /* MBAR_ETH + 0x28C */
uint32_t rmon_r_crc_align; /* MBAR_ETH + 0x290 */
uint32_t rmon_r_undersize; /* MBAR_ETH + 0x294 */
uint32_t rmon_r_oversize; /* MBAR_ETH + 0x298 */
uint32_t rmon_r_frag; /* MBAR_ETH + 0x29C */
uint32_t rmon_r_jab; /* MBAR_ETH + 0x2A0 */
uint32_t rmon_r_resvd_0; /* MBAR_ETH + 0x2A4 */
uint32_t rmon_r_p64; /* MBAR_ETH + 0x2A8 */
uint32_t rmon_r_p65to127; /* MBAR_ETH + 0x2AC */
uint32_t rmon_r_p128to255; /* MBAR_ETH + 0x2B0 */
uint32_t rmon_r_p256to511; /* MBAR_ETH + 0x2B4 */
uint32_t rmon_r_p512to1023; /* MBAR_ETH + 0x2B8 */
uint32_t rmon_r_p1024to2047; /* MBAR_ETH + 0x2BC */
uint32_t rmon_r_p_gte2048; /* MBAR_ETH + 0x2C0 */
uint32_t rmon_r_octets; /* MBAR_ETH + 0x2C4 */
uint32_t ieee_r_drop; /* MBAR_ETH + 0x2C8 */
uint32_t ieee_r_frame_ok; /* MBAR_ETH + 0x2CC */
uint32_t ieee_r_crc; /* MBAR_ETH + 0x2D0 */
uint32_t ieee_r_align; /* MBAR_ETH + 0x2D4 */
uint32_t r_macerr; /* MBAR_ETH + 0x2D8 */
uint32_t r_fdxfc; /* MBAR_ETH + 0x2DC */
uint32_t ieee_r_octets_ok; /* MBAR_ETH + 0x2E0 */
uint32_t res14[6]; /* MBAR_ETH + 0x2E4-2FC */
uint32_t res15[64]; /* MBAR_ETH + 0x300-3FF */
};
#define FEC_IEVENT_HBERR 0x80000000
#define FEC_IEVENT_BABR 0x40000000
#define FEC_IEVENT_BABT 0x20000000
#define FEC_IEVENT_GRA 0x10000000
#define FEC_IEVENT_TXF 0x08000000
#define FEC_IEVENT_TXB 0x04000000
#define FEC_IEVENT_RXF 0x02000000
#define FEC_IEVENT_RXB 0x01000000
#define FEC_IEVENT_MII 0x00800000
#define FEC_IEVENT_EBERR 0x00400000
#define FEC_IEVENT_LC 0x00200000
#define FEC_IEVENT_RL 0x00100000
#define FEC_IEVENT_UN 0x00080000
#define FEC_IMASK_HBERR 0x80000000
#define FEC_IMASK_BABR 0x40000000
#define FEC_IMASKT_BABT 0x20000000
#define FEC_IMASK_GRA 0x10000000
#define FEC_IMASKT_TXF 0x08000000
#define FEC_IMASK_TXB 0x04000000
#define FEC_IMASKT_RXF 0x02000000
#define FEC_IMASK_RXB 0x01000000
#define FEC_IMASK_MII 0x00800000
#define FEC_IMASK_EBERR 0x00400000
#define FEC_IMASK_LC 0x00200000
#define FEC_IMASKT_RL 0x00100000
#define FEC_IMASK_UN 0x00080000
#define FEC_RCNTRL_MAX_FL_SHIFT 16
#define FEC_RCNTRL_LOOP 0x00000001
#define FEC_RCNTRL_DRT 0x00000002
#define FEC_RCNTRL_MII_MODE 0x00000004
#define FEC_RCNTRL_PROM 0x00000008
#define FEC_RCNTRL_BC_REJ 0x00000010
#define FEC_RCNTRL_FCE 0x00000020
#define FEC_TCNTRL_GTS 0x00000001
#define FEC_TCNTRL_HBC 0x00000002
#define FEC_TCNTRL_FDEN 0x00000004
#define FEC_TCNTRL_TFC_PAUSE 0x00000008
#define FEC_TCNTRL_RFC_PAUSE 0x00000010
#define FEC_ECNTRL_RESET 0x00000001 /* reset the FEC */
#define FEC_ECNTRL_ETHER_EN 0x00000002 /* enable the FEC */
/**
* @brief Descriptor buffer alignment
*
* i.MX27 requires a 16 byte alignment (but for the first element only)
*/
#define DB_ALIGNMENT 16
/**
* @brief Data buffer alignment
*
* i.MX27 requires a four byte alignment for transmit and 16 bits
* alignment for receive so take 16
* Note: Valid for member data_pointer in struct buffer_descriptor
*/
#define DB_DATA_ALIGNMENT 16
/**
* @brief Receive & Transmit Buffer Descriptor definitions
*
* Note: The first BD must be aligned (see DB_ALIGNMENT)
*/
struct fec_bd {
uint16_t data_length; /* payload's length in bytes */
uint16_t status; /* BD's staus (see datasheet) */
uint32_t data_pointer; /* payload's buffer address */
};
/**
* Supported phy types on this platform
*/
enum xceiver_type {
SEVENWIRE, /* 7-wire */
MII10, /* MII 10Mbps */
MII100 /* MII 100Mbps */
};
/**
* @brief i.MX27-FEC private structure
*/
struct fec_priv {
struct ethernet_regs *eth; /* pointer to register'S base */
enum xceiver_type xcv_type; /* transceiver type */
struct fec_bd *rbd_base; /* RBD ring */
int rbd_index; /* next receive BD to read */
struct fec_bd *tbd_base; /* TBD ring */
int tbd_index; /* next transmit BD to write */
bd_t *bd;
void *rdb_ptr;
void *base_ptr;
};
/**
* @brief Numbers of buffer descriptors for receiving
*
* The number defines the stocked memory buffers for the receiving task.
* Larger values makes no sense in this limited environment.
*/
#define FEC_RBD_NUM 64
/**
* @brief Define the ethernet packet size limit in memory
*
* Note: Do not shrink this number. This will force the FEC to spread larger
* frames in more than one BD. This is nothing to worry about, but the current
* driver can't handle it.
*/
#define FEC_MAX_PKT_SIZE 1536
/* Receive BD status bits */
#define FEC_RBD_EMPTY 0x8000 /* Receive BD status: Buffer is empty */
#define FEC_RBD_WRAP 0x2000 /* Receive BD status: Last BD in ring */
/* Receive BD status: Buffer is last in frame (useless here!) */
#define FEC_RBD_LAST 0x0800
#define FEC_RBD_MISS 0x0100 /* Receive BD status: Miss bit for prom mode */
/* Receive BD status: The received frame is broadcast frame */
#define FEC_RBD_BC 0x0080
/* Receive BD status: The received frame is multicast frame */
#define FEC_RBD_MC 0x0040
#define FEC_RBD_LG 0x0020 /* Receive BD status: Frame length violation */
#define FEC_RBD_NO 0x0010 /* Receive BD status: Nonoctet align frame */
#define FEC_RBD_CR 0x0004 /* Receive BD status: CRC error */
#define FEC_RBD_OV 0x0002 /* Receive BD status: Receive FIFO overrun */
#define FEC_RBD_TR 0x0001 /* Receive BD status: Frame is truncated */
#define FEC_RBD_ERR (FEC_RBD_LG | FEC_RBD_NO | FEC_RBD_CR | \
FEC_RBD_OV | FEC_RBD_TR)
/* Transmit BD status bits */
#define FEC_TBD_READY 0x8000 /* Tansmit BD status: Buffer is ready */
#define FEC_TBD_WRAP 0x2000 /* Tansmit BD status: Mark as last BD in ring */
#define FEC_TBD_LAST 0x0800 /* Tansmit BD status: Buffer is last in frame */
#define FEC_TBD_TC 0x0400 /* Tansmit BD status: Transmit the CRC */
#define FEC_TBD_ABC 0x0200 /* Tansmit BD status: Append bad CRC */
/* MII-related definitios */
#define FEC_MII_DATA_ST 0x40000000 /* Start of frame delimiter */
#define FEC_MII_DATA_OP_RD 0x20000000 /* Perform a read operation */
#define FEC_MII_DATA_OP_WR 0x10000000 /* Perform a write operation */
#define FEC_MII_DATA_PA_MSK 0x0f800000 /* PHY Address field mask */
#define FEC_MII_DATA_RA_MSK 0x007c0000 /* PHY Register field mask */
#define FEC_MII_DATA_TA 0x00020000 /* Turnaround */
#define FEC_MII_DATA_DATAMSK 0x0000ffff /* PHY data field */
#define FEC_MII_DATA_RA_SHIFT 18 /* MII Register address bits */
#define FEC_MII_DATA_PA_SHIFT 23 /* MII PHY address bits */
#endif /* __FEC_MXC_H */

View file

@ -49,7 +49,7 @@ static int smi_reg_read(char *devname, u8 phy_adr, u8 reg_ofs, u16 * data)
struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
struct kwgbe_registers *regs = dkwgbe->regs;
u32 smi_reg;
volatile u32 timeout;
u32 timeout;
/* Phyadr read request */
if (phy_adr == 0xEE && reg_ofs == 0xEE) {
@ -124,7 +124,7 @@ static int smi_reg_write(char *devname, u8 phy_adr, u8 reg_ofs, u16 data)
struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
struct kwgbe_registers *regs = dkwgbe->regs;
u32 smi_reg;
volatile u32 timeout;
u32 timeout;
/* Phyadr write request*/
if (phy_adr == 0xEE && reg_ofs == 0xEE) {
@ -370,7 +370,7 @@ static void port_uc_addr_set(struct kwgbe_registers *regs, u8 * p_addr)
*/
static void kwgbe_init_rx_desc_ring(struct kwgbe_device *dkwgbe)
{
volatile struct kwgbe_rxdesc *p_rx_desc;
struct kwgbe_rxdesc *p_rx_desc;
int i;
/* initialize the Rx descriptors ring */
@ -487,6 +487,7 @@ static int kwgbe_send(struct eth_device *dev, volatile void *dataptr,
struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
struct kwgbe_registers *regs = dkwgbe->regs;
struct kwgbe_txdesc *p_txdesc = dkwgbe->p_txdesc;
u32 cmd_sts;
if ((u32) dataptr & 0x07) {
printf("Err..(%s) xmit dataptr not 64bit aligned\n",
@ -507,21 +508,26 @@ static int kwgbe_send(struct eth_device *dev, volatile void *dataptr,
/*
* wait for packet xmit completion
*/
while (p_txdesc->cmd_sts & KWGBE_BUFFER_OWNED_BY_DMA) {
cmd_sts = readl(&p_txdesc->cmd_sts);
while (cmd_sts & KWGBE_BUFFER_OWNED_BY_DMA) {
/* return fail if error is detected */
if (p_txdesc->cmd_sts & (KWGBE_UR_ERROR | KWGBE_RL_ERROR)) {
if ((cmd_sts & (KWGBE_ERROR_SUMMARY | KWGBE_TX_LAST_FRAME)) ==
(KWGBE_ERROR_SUMMARY | KWGBE_TX_LAST_FRAME) &&
cmd_sts & (KWGBE_UR_ERROR | KWGBE_RL_ERROR)) {
printf("Err..(%s) in xmit packet\n", __FUNCTION__);
return -1;
}
cmd_sts = readl(&p_txdesc->cmd_sts);
};
return 0;
}
static int kwgbe_recv(struct eth_device *dev)
{
volatile struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
volatile struct kwgbe_rxdesc *p_rxdesc_curr = dkwgbe->p_rxdesc_curr;
volatile u32 timeout = 0;
struct kwgbe_device *dkwgbe = to_dkwgbe(dev);
struct kwgbe_rxdesc *p_rxdesc_curr = dkwgbe->p_rxdesc_curr;
u32 cmd_sts;
u32 timeout = 0;
/* wait untill rx packet available or timeout */
do {
@ -531,7 +537,7 @@ static int kwgbe_recv(struct eth_device *dev)
debug("%s time out...\n", __FUNCTION__);
return -1;
}
} while (p_rxdesc_curr->cmd_sts & KWGBE_BUFFER_OWNED_BY_DMA);
} while (readl(&p_rxdesc_curr->cmd_sts) & KWGBE_BUFFER_OWNED_BY_DMA);
if (p_rxdesc_curr->byte_cnt != 0) {
debug("%s: Received %d byte Packet @ 0x%x (cmd_sts= %08x)\n",
@ -545,14 +551,16 @@ static int kwgbe_recv(struct eth_device *dev)
* OR the error summary bit is on,
* the packets needs to be dropeed.
*/
if ((p_rxdesc_curr->cmd_sts &
cmd_sts = readl(&p_rxdesc_curr->cmd_sts);
if ((cmd_sts &
(KWGBE_RX_FIRST_DESC | KWGBE_RX_LAST_DESC))
!= (KWGBE_RX_FIRST_DESC | KWGBE_RX_LAST_DESC)) {
printf("Err..(%s) Dropping packet spread on"
" multiple descriptors\n", __FUNCTION__);
} else if (p_rxdesc_curr->cmd_sts & KWGBE_ERROR_SUMMARY) {
} else if (cmd_sts & KWGBE_ERROR_SUMMARY) {
printf("Err..(%s) Dropping packet with errors\n",
__FUNCTION__);
@ -574,7 +582,8 @@ static int kwgbe_recv(struct eth_device *dev)
p_rxdesc_curr->buf_size = PKTSIZE_ALIGN;
p_rxdesc_curr->byte_cnt = 0;
dkwgbe->p_rxdesc_curr = p_rxdesc_curr->nxtdesc_p;
writel((unsigned)p_rxdesc_curr->nxtdesc_p, &dkwgbe->p_rxdesc_curr);
return 0;
}

View file

@ -256,6 +256,7 @@
#define KWGBE_UR_ERROR (1 << 1)
#define KWGBE_RL_ERROR (1 << 2)
#define KWGBE_LLC_SNAP_FORMAT (1 << 9)
#define KWGBE_TX_LAST_FRAME (1 << 20)
/* Rx descriptors status */
#define KWGBE_CRC_ERROR 0

View file

@ -127,6 +127,11 @@ int bb_miiphy_read (char *devname, unsigned char addr,
volatile ioport_t *iop = ioport_addr ((immap_t *) CONFIG_SYS_IMMR, MDIO_PORT);
#endif
if (value == NULL) {
puts("NULL value pointer\n");
return (-1);
}
miiphy_pre (1, addr, reg);
/* tri-state our MDIO I/O pin so we can read */
@ -145,6 +150,8 @@ int bb_miiphy_read (char *devname, unsigned char addr,
MDC (1);
MIIDELAY;
}
/* There is no PHY, set value to 0xFFFF and return */
*value = 0xFFFF;
return (-1);
}

View file

@ -36,7 +36,7 @@
* By default single chip mode is configured
* multichip mode operation can be configured in board header
*/
static int mv88e61xx_busychk_multic(u32 devaddr)
static int mv88e61xx_busychk_multic(char *name, u32 devaddr)
{
u32 reg = 0;
u32 timeout = MV88E61XX_PHY_TIMEOUT;
@ -58,11 +58,11 @@ static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data)
u32 mii_dev_addr;
/* command to read PHY dev address */
if (!miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) {
if (miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) {
printf("Error..could not read PHY dev address\n");
return;
}
mv88e61xx_busychk_multic(mii_dev_addr);
mv88e61xx_busychk_multic(name, mii_dev_addr);
/* Write data to Switch indirect data register */
miiphy_write(name, mii_dev_addr, 0x1, data);
/* Write command to Switch indirect command register (write) */
@ -77,18 +77,18 @@ static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data)
u32 mii_dev_addr;
/* command to read PHY dev address */
if (!miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) {
if (miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) {
printf("Error..could not read PHY dev address\n");
return;
}
mv88e61xx_busychk_multic(mii_dev_addr);
mv88e61xx_busychk_multic(name, mii_dev_addr);
/* Write command to Switch indirect command register (read) */
miiphy_write(name, mii_dev_addr, 0x0,
reg_ofs | (phy_adr << 5) | (1 << 10) | (1 << 12) | (1 <<
reg_ofs | (phy_adr << 5) | (1 << 11) | (1 << 12) | (1 <<
15));
mv88e61xx_busychk_multic(mii_dev_addr);
mv88e61xx_busychk_multic(name, mii_dev_addr);
/* Read data from Switch indirect data register */
miiphy_read(name, mii_dev_addr, 0x1, (u16 *) & data);
miiphy_read(name, mii_dev_addr, 0x1, data);
}
#endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */
@ -212,7 +212,7 @@ static int mv88e61xx_busychk(char *name)
printf("SMI busy timeout\n");
return -1;
}
} while (reg & 1 << 28); /* busy mask */
} while (reg & 1 << 15); /* busy mask */
return 0;
}

View file

@ -49,7 +49,7 @@
#define MV88E61XX_ADDR_OFST 5
#ifdef CONFIG_MV88E61XX_MULTICHIP_ADRMODE
static int mv88e61xx_busychk_multic(u32 devaddr);
static int mv88e61xx_busychk_multic(char *name, u32 devaddr);
static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data);
static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data);
#define WR_PHY mv88e61xx_wr_phy

View file

@ -546,7 +546,7 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd)
/* Configure phy */
ret = sh_eth_phy_config(eth);
if (ret) {
printf(SHETHER_NAME ":i phy config timeout\n");
printf(SHETHER_NAME ": phy config timeout\n");
goto err_phy_cfg;
}
/* Read phy status to finish configuring the e-mac */

View file

@ -24,110 +24,90 @@
#include <common.h>
#include <command.h>
#include <malloc.h>
#include <net.h>
#include <miiphy.h>
#include "smc911x.h"
u32 pkt_data_pull(u32 addr) \
u32 pkt_data_pull(struct eth_device *dev, u32 addr) \
__attribute__ ((weak, alias ("smc911x_reg_read")));
void pkt_data_push(u32 addr, u32 val) \
void pkt_data_push(struct eth_device *dev, u32 addr, u32 val) \
__attribute__ ((weak, alias ("smc911x_reg_write")));
#define mdelay(n) udelay((n)*1000)
static int smx911x_handle_mac_address(bd_t *bd)
static void smx911x_handle_mac_address(struct eth_device *dev)
{
unsigned long addrh, addrl;
uchar m[6];
uchar *m = dev->enetaddr;
if (eth_getenv_enetaddr("ethaddr", m)) {
/* if the environment has a valid mac address then use it */
addrl = m[0] | (m[1] << 8) | (m[2] << 16) | (m[3] << 24);
addrh = m[4] | (m[5] << 8);
smc911x_set_mac_csr(ADDRL, addrl);
smc911x_set_mac_csr(ADDRH, addrh);
} else {
/* if not, try to get one from the eeprom */
addrh = smc911x_get_mac_csr(ADDRH);
addrl = smc911x_get_mac_csr(ADDRL);
m[0] = (addrl ) & 0xff;
m[1] = (addrl >> 8 ) & 0xff;
m[2] = (addrl >> 16 ) & 0xff;
m[3] = (addrl >> 24 ) & 0xff;
m[4] = (addrh ) & 0xff;
m[5] = (addrh >> 8 ) & 0xff;
/* we get 0xff when there is no eeprom connected */
if ((m[0] & m[1] & m[2] & m[3] & m[4] & m[5]) == 0xff) {
printf(DRIVERNAME ": no valid mac address in environment "
"and no eeprom found\n");
return -1;
}
eth_setenv_enetaddr("ethaddr", m);
}
addrl = m[0] | (m[1] << 8) | (m[2] << 16) | (m[3] << 24);
addrh = m[4] | (m[5] << 8);
smc911x_set_mac_csr(dev, ADDRL, addrl);
smc911x_set_mac_csr(dev, ADDRH, addrh);
printf(DRIVERNAME ": MAC %pM\n", m);
}
static int smc911x_miiphy_read(struct eth_device *dev,
u8 phy, u8 reg, u16 *val)
{
while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY)
;
smc911x_set_mac_csr(dev, MII_ACC, phy << 11 | reg << 6 |
MII_ACC_MII_BUSY);
while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY)
;
*val = smc911x_get_mac_csr(dev, MII_DATA);
return 0;
}
static int smc911x_miiphy_read(u8 phy, u8 reg, u16 *val)
static int smc911x_miiphy_write(struct eth_device *dev,
u8 phy, u8 reg, u16 val)
{
while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY)
while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY)
;
smc911x_set_mac_csr(MII_ACC, phy << 11 | reg << 6 | MII_ACC_MII_BUSY);
while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY)
;
*val = smc911x_get_mac_csr(MII_DATA);
return 0;
}
static int smc911x_miiphy_write(u8 phy, u8 reg, u16 val)
{
while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY)
;
smc911x_set_mac_csr(MII_DATA, val);
smc911x_set_mac_csr(MII_ACC,
smc911x_set_mac_csr(dev, MII_DATA, val);
smc911x_set_mac_csr(dev, MII_ACC,
phy << 11 | reg << 6 | MII_ACC_MII_BUSY | MII_ACC_MII_WRITE);
while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY)
while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY)
;
return 0;
}
static int smc911x_phy_reset(void)
static int smc911x_phy_reset(struct eth_device *dev)
{
u32 reg;
reg = smc911x_reg_read(PMT_CTRL);
reg = smc911x_reg_read(dev, PMT_CTRL);
reg &= ~0xfffff030;
reg |= PMT_CTRL_PHY_RST;
smc911x_reg_write(PMT_CTRL, reg);
smc911x_reg_write(dev, PMT_CTRL, reg);
mdelay(100);
return 0;
}
static void smc911x_phy_configure(void)
static void smc911x_phy_configure(struct eth_device *dev)
{
int timeout;
u16 status;
smc911x_phy_reset();
smc911x_phy_reset(dev);
smc911x_miiphy_write(1, PHY_BMCR, PHY_BMCR_RESET);
smc911x_miiphy_write(dev, 1, PHY_BMCR, PHY_BMCR_RESET);
mdelay(1);
smc911x_miiphy_write(1, PHY_ANAR, 0x01e1);
smc911x_miiphy_write(1, PHY_BMCR, PHY_BMCR_AUTON | PHY_BMCR_RST_NEG);
smc911x_miiphy_write(dev, 1, PHY_ANAR, 0x01e1);
smc911x_miiphy_write(dev, 1, PHY_BMCR, PHY_BMCR_AUTON |
PHY_BMCR_RST_NEG);
timeout = 5000;
do {
@ -135,7 +115,7 @@ static void smc911x_phy_configure(void)
if ((timeout--) == 0)
goto err_out;
if (smc911x_miiphy_read(1, PHY_BMSR, &status) != 0)
if (smc911x_miiphy_read(dev, 1, PHY_BMSR, &status) != 0)
goto err_out;
} while (!(status & PHY_BMSR_LS));
@ -147,39 +127,39 @@ err_out:
printf(DRIVERNAME ": autonegotiation timed out\n");
}
static void smc911x_enable(void)
static void smc911x_enable(struct eth_device *dev)
{
/* Enable TX */
smc911x_reg_write(HW_CFG, 8 << 16 | HW_CFG_SF);
smc911x_reg_write(dev, HW_CFG, 8 << 16 | HW_CFG_SF);
smc911x_reg_write(GPT_CFG, GPT_CFG_TIMER_EN | 10000);
smc911x_reg_write(dev, GPT_CFG, GPT_CFG_TIMER_EN | 10000);
smc911x_reg_write(TX_CFG, TX_CFG_TX_ON);
smc911x_reg_write(dev, TX_CFG, TX_CFG_TX_ON);
/* no padding to start of packets */
smc911x_reg_write(RX_CFG, 0);
smc911x_reg_write(dev, RX_CFG, 0);
smc911x_set_mac_csr(MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN | MAC_CR_HBDIS);
smc911x_set_mac_csr(dev, MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN |
MAC_CR_HBDIS);
}
int eth_init(bd_t *bd)
static int smc911x_init(struct eth_device *dev, bd_t * bd)
{
printf(DRIVERNAME ": initializing\n");
if (smc911x_detect_chip())
if (smc911x_detect_chip(dev))
goto err_out;
smc911x_reset();
smc911x_reset(dev);
/* Configure the PHY, initialize the link state */
smc911x_phy_configure();
smc911x_phy_configure(dev);
if (smx911x_handle_mac_address(bd))
goto err_out;
smx911x_handle_mac_address(dev);
/* Turn on Tx + Rx */
smc911x_enable();
smc911x_enable(dev);
return 0;
@ -187,28 +167,32 @@ err_out:
return -1;
}
int eth_send(volatile void *packet, int length)
static int smc911x_send(struct eth_device *dev,
volatile void *packet, int length)
{
u32 *data = (u32*)packet;
u32 tmplen;
u32 status;
smc911x_reg_write(TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG | TX_CMD_A_INT_LAST_SEG | length);
smc911x_reg_write(TX_DATA_FIFO, length);
smc911x_reg_write(dev, TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG |
TX_CMD_A_INT_LAST_SEG | length);
smc911x_reg_write(dev, TX_DATA_FIFO, length);
tmplen = (length + 3) / 4;
while (tmplen--)
pkt_data_push(TX_DATA_FIFO, *data++);
pkt_data_push(dev, TX_DATA_FIFO, *data++);
/* wait for transmission */
while (!((smc911x_reg_read(TX_FIFO_INF) & TX_FIFO_INF_TSUSED) >> 16));
while (!((smc911x_reg_read(dev, TX_FIFO_INF) &
TX_FIFO_INF_TSUSED) >> 16));
/* get status. Ignore 'no carrier' error, it has no meaning for
* full duplex operation
*/
status = smc911x_reg_read(TX_STATUS_FIFO) & (TX_STS_LOC | TX_STS_LATE_COLL |
TX_STS_MANY_COLL | TX_STS_MANY_DEFER | TX_STS_UNDERRUN);
status = smc911x_reg_read(dev, TX_STATUS_FIFO) &
(TX_STS_LOC | TX_STS_LATE_COLL | TX_STS_MANY_COLL |
TX_STS_MANY_DEFER | TX_STS_UNDERRUN);
if (!status)
return 0;
@ -223,26 +207,26 @@ int eth_send(volatile void *packet, int length)
return -1;
}
void eth_halt(void)
static void smc911x_halt(struct eth_device *dev)
{
smc911x_reset();
smc911x_reset(dev);
}
int eth_rx(void)
static int smc911x_rx(struct eth_device *dev)
{
u32 *data = (u32 *)NetRxPackets[0];
u32 pktlen, tmplen;
u32 status;
if ((smc911x_reg_read(RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) {
status = smc911x_reg_read(RX_STATUS_FIFO);
if ((smc911x_reg_read(dev, RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) {
status = smc911x_reg_read(dev, RX_STATUS_FIFO);
pktlen = (status & RX_STS_PKT_LEN) >> 16;
smc911x_reg_write(RX_CFG, 0);
smc911x_reg_write(dev, RX_CFG, 0);
tmplen = (pktlen + 2+ 3) / 4;
while (tmplen--)
*data++ = pkt_data_pull(RX_DATA_FIFO);
*data++ = pkt_data_pull(dev, RX_DATA_FIFO);
if (status & RX_STS_ES)
printf(DRIVERNAME
@ -254,3 +238,36 @@ int eth_rx(void)
return 0;
}
int smc911x_initialize(u8 dev_num, int base_addr)
{
unsigned long addrl, addrh;
struct eth_device *dev;
dev = malloc(sizeof(*dev));
if (!dev) {
free(dev);
return 0;
}
memset(dev, 0, sizeof(*dev));
dev->iobase = base_addr;
addrh = smc911x_get_mac_csr(dev, ADDRH);
addrl = smc911x_get_mac_csr(dev, ADDRL);
dev->enetaddr[0] = addrl;
dev->enetaddr[1] = addrl >> 8;
dev->enetaddr[2] = addrl >> 16;
dev->enetaddr[3] = addrl >> 24;
dev->enetaddr[4] = addrh;
dev->enetaddr[5] = addrh >> 8;
dev->init = smc911x_init;
dev->halt = smc911x_halt;
dev->send = smc911x_send;
dev->recv = smc911x_rx;
sprintf(dev->name, "%s-%hu", DRIVERNAME, dev_num);
eth_register(dev);
return 0;
}

View file

@ -27,45 +27,51 @@
#include <linux/types.h>
#if defined (CONFIG_DRIVER_SMC911X_32_BIT) && \
defined (CONFIG_DRIVER_SMC911X_16_BIT)
#error "SMC911X: Only one of CONFIG_DRIVER_SMC911X_32_BIT and \
CONFIG_DRIVER_SMC911X_16_BIT shall be set"
#define DRIVERNAME "smc911x"
#if defined (CONFIG_SMC911X_32_BIT) && \
defined (CONFIG_SMC911X_16_BIT)
#error "SMC911X: Only one of CONFIG_SMC911X_32_BIT and \
CONFIG_SMC911X_16_BIT shall be set"
#endif
#if defined (CONFIG_DRIVER_SMC911X_32_BIT)
static inline u32 __smc911x_reg_read(u32 addr)
#if defined (CONFIG_SMC911X_32_BIT)
static inline u32 __smc911x_reg_read(struct eth_device *dev, u32 offset)
{
return *(volatile u32*)addr;
return *(volatile u32*)(dev->iobase + offset);
}
u32 smc911x_reg_read(u32 addr) __attribute__((weak, alias("__smc911x_reg_read")));
u32 smc911x_reg_read(struct eth_device *dev, u32 offset)
__attribute__((weak, alias("__smc911x_reg_read")));
static inline void __smc911x_reg_write(u32 addr, u32 val)
static inline void __smc911x_reg_write(struct eth_device *dev,
u32 offset, u32 val)
{
*(volatile u32*)addr = val;
*(volatile u32*)(dev->iobase + offset) = val;
}
void smc911x_reg_write(u32 addr, u32 val) __attribute__((weak, alias("__smc911x_reg_write")));
#elif defined (CONFIG_DRIVER_SMC911X_16_BIT)
static inline u32 smc911x_reg_read(u32 addr)
void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val)
__attribute__((weak, alias("__smc911x_reg_write")));
#elif defined (CONFIG_SMC911X_16_BIT)
static inline u32 smc911x_reg_read(struct eth_device *dev, u32 offset)
{
volatile u16 *addr_16 = (u16 *)addr;
volatile u16 *addr_16 = (u16 *)(dev->iobase + offset);
return ((*addr_16 & 0x0000ffff) | (*(addr_16 + 1) << 16));
}
static inline void smc911x_reg_write(u32 addr, u32 val)
static inline void smc911x_reg_write(struct eth_device *dev,
u32 offset, u32 val)
{
*(volatile u16*)addr = (u16)val;
*(volatile u16*)(addr + 2) = (u16)(val >> 16);
*(volatile u16 *)(dev->iobase + offset) = (u16)val;
*(volatile u16 *)(dev->iobase + offset + 2) = (u16)(val >> 16);
}
#else
#error "SMC911X: undefined bus width"
#endif /* CONFIG_DRIVER_SMC911X_16_BIT */
#endif /* CONFIG_SMC911X_16_BIT */
/* Below are the register offsets and bit definitions
* of the Lan911x memory space
*/
#define RX_DATA_FIFO (CONFIG_DRIVER_SMC911X_BASE + 0x00)
#define RX_DATA_FIFO 0x00
#define TX_DATA_FIFO (CONFIG_DRIVER_SMC911X_BASE + 0x20)
#define TX_DATA_FIFO 0x20
#define TX_CMD_A_INT_ON_COMP 0x80000000
#define TX_CMD_A_INT_BUF_END_ALGN 0x03000000
#define TX_CMD_A_INT_4_BYTE_ALGN 0x00000000
@ -80,7 +86,7 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
#define TX_CMD_B_DISABLE_PADDING 0x00001000
#define TX_CMD_B_PKT_BYTE_LENGTH 0x000007FF
#define RX_STATUS_FIFO (CONFIG_DRIVER_SMC911X_BASE + 0x40)
#define RX_STATUS_FIFO 0x40
#define RX_STS_PKT_LEN 0x3FFF0000
#define RX_STS_ES 0x00008000
#define RX_STS_BCST 0x00002000
@ -94,8 +100,8 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
#define RX_STS_MII_ERR 0x00000008
#define RX_STS_DRIBBLING 0x00000004
#define RX_STS_CRC_ERR 0x00000002
#define RX_STATUS_FIFO_PEEK (CONFIG_DRIVER_SMC911X_BASE + 0x44)
#define TX_STATUS_FIFO (CONFIG_DRIVER_SMC911X_BASE + 0x48)
#define RX_STATUS_FIFO_PEEK 0x44
#define TX_STATUS_FIFO 0x48
#define TX_STS_TAG 0xFFFF0000
#define TX_STS_ES 0x00008000
#define TX_STS_LOC 0x00000800
@ -106,21 +112,23 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
#define TX_STS_MANY_DEFER 0x00000004
#define TX_STS_UNDERRUN 0x00000002
#define TX_STS_DEFERRED 0x00000001
#define TX_STATUS_FIFO_PEEK (CONFIG_DRIVER_SMC911X_BASE + 0x4C)
#define ID_REV (CONFIG_DRIVER_SMC911X_BASE + 0x50)
#define TX_STATUS_FIFO_PEEK 0x4C
#define ID_REV 0x50
#define ID_REV_CHIP_ID 0xFFFF0000 /* RO */
#define ID_REV_REV_ID 0x0000FFFF /* RO */
#define INT_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x54)
#define INT_CFG 0x54
#define INT_CFG_INT_DEAS 0xFF000000 /* R/W */
#define INT_CFG_INT_DEAS_CLR 0x00004000
#define INT_CFG_INT_DEAS_STS 0x00002000
#define INT_CFG_IRQ_INT 0x00001000 /* RO */
#define INT_CFG_IRQ_EN 0x00000100 /* R/W */
#define INT_CFG_IRQ_POL 0x00000010 /* R/W Not Affected by SW Reset */
#define INT_CFG_IRQ_TYPE 0x00000001 /* R/W Not Affected by SW Reset */
/* R/W Not Affected by SW Reset */
#define INT_CFG_IRQ_POL 0x00000010
/* R/W Not Affected by SW Reset */
#define INT_CFG_IRQ_TYPE 0x00000001
#define INT_STS (CONFIG_DRIVER_SMC911X_BASE + 0x58)
#define INT_STS 0x58
#define INT_STS_SW_INT 0x80000000 /* R/WC */
#define INT_STS_TXSTOP_INT 0x02000000 /* R/WC */
#define INT_STS_RXSTOP_INT 0x01000000 /* R/WC */
@ -149,7 +157,7 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
#define INT_STS_GPIO2_INT 0x00000004 /* R/WC */
#define INT_STS_GPIO1_INT 0x00000002 /* R/WC */
#define INT_STS_GPIO0_INT 0x00000001 /* R/WC */
#define INT_EN (CONFIG_DRIVER_SMC911X_BASE + 0x5C)
#define INT_EN 0x5C
#define INT_EN_SW_INT_EN 0x80000000 /* R/W */
#define INT_EN_TXSTOP_INT_EN 0x02000000 /* R/W */
#define INT_EN_RXSTOP_INT_EN 0x01000000 /* R/W */
@ -179,14 +187,14 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
#define INT_EN_GPIO1_INT 0x00000002 /* R/W */
#define INT_EN_GPIO0_INT 0x00000001 /* R/W */
#define BYTE_TEST (CONFIG_DRIVER_SMC911X_BASE + 0x64)
#define FIFO_INT (CONFIG_DRIVER_SMC911X_BASE + 0x68)
#define BYTE_TEST 0x64
#define FIFO_INT 0x68
#define FIFO_INT_TX_AVAIL_LEVEL 0xFF000000 /* R/W */
#define FIFO_INT_TX_STS_LEVEL 0x00FF0000 /* R/W */
#define FIFO_INT_RX_AVAIL_LEVEL 0x0000FF00 /* R/W */
#define FIFO_INT_RX_STS_LEVEL 0x000000FF /* R/W */
#define RX_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x6C)
#define RX_CFG 0x6C
#define RX_CFG_RX_END_ALGN 0xC0000000 /* R/W */
#define RX_CFG_RX_END_ALGN4 0x00000000 /* R/W */
#define RX_CFG_RX_END_ALGN16 0x40000000 /* R/W */
@ -196,16 +204,17 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
#define RX_CFG_RXDOFF 0x00001F00 /* R/W */
/*#define RX_CFG_RXBAD 0x00000001*/ /* R/W */
#define TX_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x70)
#define TX_CFG 0x70
/*#define TX_CFG_TX_DMA_LVL 0xE0000000*/ /* R/W */
/*#define TX_CFG_TX_DMA_CNT 0x0FFF0000*/ /* R/W Self Clearing */
/* R/W Self Clearing */
/*#define TX_CFG_TX_DMA_CNT 0x0FFF0000*/
#define TX_CFG_TXS_DUMP 0x00008000 /* Self Clearing */
#define TX_CFG_TXD_DUMP 0x00004000 /* Self Clearing */
#define TX_CFG_TXSAO 0x00000004 /* R/W */
#define TX_CFG_TX_ON 0x00000002 /* R/W */
#define TX_CFG_STOP_TX 0x00000001 /* Self Clearing */
#define HW_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x74)
#define HW_CFG 0x74
#define HW_CFG_TTM 0x00200000 /* R/W */
#define HW_CFG_SF 0x00100000 /* R/W */
#define HW_CFG_TX_FIF_SZ 0x000F0000 /* R/W */
@ -221,24 +230,25 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
#define HW_CFG_SRST_TO 0x00000002 /* RO */
#define HW_CFG_SRST 0x00000001 /* Self Clearing */
#define RX_DP_CTRL (CONFIG_DRIVER_SMC911X_BASE + 0x78)
#define RX_DP_CTRL 0x78
#define RX_DP_CTRL_RX_FFWD 0x80000000 /* R/W */
#define RX_DP_CTRL_FFWD_BUSY 0x80000000 /* RO */
#define RX_FIFO_INF (CONFIG_DRIVER_SMC911X_BASE + 0x7C)
#define RX_FIFO_INF 0x7C
#define RX_FIFO_INF_RXSUSED 0x00FF0000 /* RO */
#define RX_FIFO_INF_RXDUSED 0x0000FFFF /* RO */
#define TX_FIFO_INF (CONFIG_DRIVER_SMC911X_BASE + 0x80)
#define TX_FIFO_INF 0x80
#define TX_FIFO_INF_TSUSED 0x00FF0000 /* RO */
#define TX_FIFO_INF_TDFREE 0x0000FFFF /* RO */
#define PMT_CTRL (CONFIG_DRIVER_SMC911X_BASE + 0x84)
#define PMT_CTRL 0x84
#define PMT_CTRL_PM_MODE 0x00003000 /* Self Clearing */
#define PMT_CTRL_PHY_RST 0x00000400 /* Self Clearing */
#define PMT_CTRL_WOL_EN 0x00000200 /* R/W */
#define PMT_CTRL_ED_EN 0x00000100 /* R/W */
#define PMT_CTRL_PME_TYPE 0x00000040 /* R/W Not Affected by SW Reset */
/* R/W Not Affected by SW Reset */
#define PMT_CTRL_PME_TYPE 0x00000040
#define PMT_CTRL_WUPS 0x00000030 /* R/WC */
#define PMT_CTRL_WUPS_NOWAKE 0x00000000 /* R/WC */
#define PMT_CTRL_WUPS_ED 0x00000010 /* R/WC */
@ -246,10 +256,11 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
#define PMT_CTRL_WUPS_MULTI 0x00000030 /* R/WC */
#define PMT_CTRL_PME_IND 0x00000008 /* R/W */
#define PMT_CTRL_PME_POL 0x00000004 /* R/W */
#define PMT_CTRL_PME_EN 0x00000002 /* R/W Not Affected by SW Reset */
/* R/W Not Affected by SW Reset */
#define PMT_CTRL_PME_EN 0x00000002
#define PMT_CTRL_READY 0x00000001 /* RO */
#define GPIO_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x88)
#define GPIO_CFG 0x88
#define GPIO_CFG_LED3_EN 0x40000000 /* R/W */
#define GPIO_CFG_LED2_EN 0x20000000 /* R/W */
#define GPIO_CFG_LED1_EN 0x10000000 /* R/W */
@ -269,23 +280,23 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
#define GPIO_CFG_GPIOD1 0x00000002 /* R/W */
#define GPIO_CFG_GPIOD0 0x00000001 /* R/W */
#define GPT_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x8C)
#define GPT_CFG 0x8C
#define GPT_CFG_TIMER_EN 0x20000000 /* R/W */
#define GPT_CFG_GPT_LOAD 0x0000FFFF /* R/W */
#define GPT_CNT (CONFIG_DRIVER_SMC911X_BASE + 0x90)
#define GPT_CNT 0x90
#define GPT_CNT_GPT_CNT 0x0000FFFF /* RO */
#define ENDIAN (CONFIG_DRIVER_SMC911X_BASE + 0x98)
#define FREE_RUN (CONFIG_DRIVER_SMC911X_BASE + 0x9C)
#define RX_DROP (CONFIG_DRIVER_SMC911X_BASE + 0xA0)
#define MAC_CSR_CMD (CONFIG_DRIVER_SMC911X_BASE + 0xA4)
#define ENDIAN 0x98
#define FREE_RUN 0x9C
#define RX_DROP 0xA0
#define MAC_CSR_CMD 0xA4
#define MAC_CSR_CMD_CSR_BUSY 0x80000000 /* Self Clearing */
#define MAC_CSR_CMD_R_NOT_W 0x40000000 /* R/W */
#define MAC_CSR_CMD_CSR_ADDR 0x000000FF /* R/W */
#define MAC_CSR_DATA (CONFIG_DRIVER_SMC911X_BASE + 0xA8)
#define AFC_CFG (CONFIG_DRIVER_SMC911X_BASE + 0xAC)
#define MAC_CSR_DATA 0xA8
#define AFC_CFG 0xAC
#define AFC_CFG_AFC_HI 0x00FF0000 /* R/W */
#define AFC_CFG_AFC_LO 0x0000FF00 /* R/W */
#define AFC_CFG_BACK_DUR 0x000000F0 /* R/W */
@ -294,7 +305,7 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
#define AFC_CFG_FCADD 0x00000002 /* R/W */
#define AFC_CFG_FCANY 0x00000001 /* R/W */
#define E2P_CMD (CONFIG_DRIVER_SMC911X_BASE + 0xB0)
#define E2P_CMD 0xB0
#define E2P_CMD_EPC_BUSY 0x80000000 /* Self Clearing */
#define E2P_CMD_EPC_CMD 0x70000000 /* R/W */
#define E2P_CMD_EPC_CMD_READ 0x00000000 /* R/W */
@ -309,7 +320,7 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
#define E2P_CMD_MAC_ADDR_LOADED 0x00000100 /* RO */
#define E2P_CMD_EPC_ADDR 0x000000FF /* R/W */
#define E2P_DATA (CONFIG_DRIVER_SMC911X_BASE + 0xB4)
#define E2P_DATA 0xB4
#define E2P_DATA_EEPROM_DATA 0x000000FF /* R/W */
/* end of LAN register offsets and bit definitions */
@ -382,6 +393,7 @@ static inline void smc911x_reg_write(u32 addr, u32 val)
#define CHIP_9216 0x116a
#define CHIP_9217 0x117a
#define CHIP_9218 0x118a
#define CHIP_9221 0x9221
struct chip_id {
u16 id;
@ -398,44 +410,43 @@ static const struct chip_id chip_ids[] = {
{ CHIP_9216, "LAN9216" },
{ CHIP_9217, "LAN9217" },
{ CHIP_9218, "LAN9218" },
{ CHIP_9221, "LAN9221" },
{ 0, NULL },
};
#define DRIVERNAME "smc911x"
static u32 smc911x_get_mac_csr(u8 reg)
static u32 smc911x_get_mac_csr(struct eth_device *dev, u8 reg)
{
while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
;
smc911x_reg_write(MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg);
while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
smc911x_reg_write(dev, MAC_CSR_CMD,
MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg);
while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
;
return smc911x_reg_read(MAC_CSR_DATA);
return smc911x_reg_read(dev, MAC_CSR_DATA);
}
static void smc911x_set_mac_csr(u8 reg, u32 data)
static void smc911x_set_mac_csr(struct eth_device *dev, u8 reg, u32 data)
{
while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
;
smc911x_reg_write(MAC_CSR_DATA, data);
smc911x_reg_write(MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg);
while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
smc911x_reg_write(dev, MAC_CSR_DATA, data);
smc911x_reg_write(dev, MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg);
while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
;
}
static int smc911x_detect_chip(void)
static int smc911x_detect_chip(struct eth_device *dev)
{
unsigned long val, i;
val = smc911x_reg_read(BYTE_TEST);
val = smc911x_reg_read(dev, BYTE_TEST);
if (val != 0x87654321) {
printf(DRIVERNAME ": Invalid chip endian 0x%08lx\n", val);
return -1;
}
val = smc911x_reg_read(ID_REV) >> 16;
val = smc911x_reg_read(dev, ID_REV) >> 16;
for (i = 0; chip_ids[i].id != 0; i++) {
if (chip_ids[i].id == val) break;
}
@ -449,18 +460,19 @@ static int smc911x_detect_chip(void)
return 0;
}
static void smc911x_reset(void)
static void smc911x_reset(struct eth_device *dev)
{
int timeout;
/* Take out of PM setting first */
if (smc911x_reg_read(PMT_CTRL) & PMT_CTRL_READY) {
if (smc911x_reg_read(dev, PMT_CTRL) & PMT_CTRL_READY) {
/* Write to the bytetest will take out of powerdown */
smc911x_reg_write(BYTE_TEST, 0x0);
smc911x_reg_write(dev, BYTE_TEST, 0x0);
timeout = 10;
while (timeout-- && !(smc911x_reg_read(PMT_CTRL) & PMT_CTRL_READY))
while (timeout-- &&
!(smc911x_reg_read(dev, PMT_CTRL) & PMT_CTRL_READY))
udelay(10);
if (!timeout) {
printf(DRIVERNAME
@ -470,12 +482,12 @@ static void smc911x_reset(void)
}
/* Disable interrupts */
smc911x_reg_write(INT_EN, 0);
smc911x_reg_write(dev, INT_EN, 0);
smc911x_reg_write(HW_CFG, HW_CFG_SRST);
smc911x_reg_write(dev, HW_CFG, HW_CFG_SRST);
timeout = 1000;
while (timeout-- && smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY)
while (timeout-- && smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY)
udelay(10);
if (!timeout) {
@ -484,11 +496,11 @@ static void smc911x_reset(void)
}
/* Reset the FIFO level and flow control settings */
smc911x_set_mac_csr(FLOW, FLOW_FCPT | FLOW_FCEN);
smc911x_reg_write(AFC_CFG, 0x0050287F);
smc911x_set_mac_csr(dev, FLOW, FLOW_FCPT | FLOW_FCEN);
smc911x_reg_write(dev, AFC_CFG, 0x0050287F);
/* Set to LED outputs */
smc911x_reg_write(GPIO_CFG, 0x70070000);
smc911x_reg_write(dev, GPIO_CFG, 0x70070000);
}
#endif

View file

@ -5,7 +5,7 @@
* terms of the GNU Public License, Version 2, incorporated
* herein by reference.
*
* Copyright 2004, 2007 Freescale Semiconductor, Inc.
* Copyright (C) 2004-2009 Freescale Semiconductor, Inc. All rights reserved.
* (C) Copyright 2003, Motorola, Inc.
* author Andy Fleming
*
@ -197,7 +197,10 @@ int tsec_init(struct eth_device *dev, bd_t * bd)
for (i = 0; i < MAC_ADDR_LEN; i++) {
tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i];
}
regs->macstnaddr1 = *((uint *) (tmpbuf));
tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) |
tmpbuf[3];
regs->macstnaddr1 = tempval;
tempval = *((uint *) (tmpbuf + 4));
@ -1426,6 +1429,54 @@ struct phy_info phy_info_VSC8244 = {
},
};
struct phy_info phy_info_VSC8641 = {
0x7043,
"Vitesse VSC8641",
4,
(struct phy_cmd[]){ /* config */
/* Configure some basic stuff */
{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
{miim_end,}
},
(struct phy_cmd[]){ /* startup */
/* Read the Status (2x to make sure link is right) */
{MIIM_STATUS, miim_read, NULL},
/* Auto-negotiate */
{MIIM_STATUS, miim_read, &mii_parse_sr},
/* Read the status */
{MIIM_VSC8244_AUX_CONSTAT, miim_read,
&mii_parse_vsc8244},
{miim_end,}
},
(struct phy_cmd[]){ /* shutdown */
{miim_end,}
},
};
struct phy_info phy_info_VSC8221 = {
0xfc55,
"Vitesse VSC8221",
4,
(struct phy_cmd[]){ /* config */
/* Configure some basic stuff */
{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
{miim_end,}
},
(struct phy_cmd[]){ /* startup */
/* Read the Status (2x to make sure link is right) */
{MIIM_STATUS, miim_read, NULL},
/* Auto-negotiate */
{MIIM_STATUS, miim_read, &mii_parse_sr},
/* Read the status */
{MIIM_VSC8244_AUX_CONSTAT, miim_read,
&mii_parse_vsc8244},
{miim_end,}
},
(struct phy_cmd[]){ /* shutdown */
{miim_end,}
},
};
struct phy_info phy_info_VSC8601 = {
0x00007042,
"Vitesse VSC8601",
@ -1663,6 +1714,8 @@ struct phy_info *phy_info[] = {
&phy_info_VSC8211,
&phy_info_VSC8244,
&phy_info_VSC8601,
&phy_info_VSC8641,
&phy_info_VSC8221,
&phy_info_dp83865,
&phy_info_rtl8211b,
&phy_info_generic, /* must be last; has ID 0 and 32 bit mask */

View file

@ -53,9 +53,10 @@
#undef CONFIG_SHOW_BOOT_PROGRESS
/* SMC9118 */
#define CONFIG_DRIVER_SMC911X 1
#define CONFIG_DRIVER_SMC911X_32_BIT 1
#define CONFIG_DRIVER_SMC911X_BASE 0xB6080000
#define CONFIG_NET_MULTI
#define CONFIG_SMC911X 1
#define CONFIG_SMC911X_32_BIT 1
#define CONFIG_SMC911X_BASE 0xB6080000
/* MEMORY */
#define AP325RXA_SDRAM_BASE (0x88000000)

View file

@ -69,9 +69,10 @@
* Network Settings
*/
#define ADI_CMDS_NETWORK 1
#define CONFIG_DRIVER_SMC911X 1
#define CONFIG_DRIVER_SMC911X_BASE 0x24000000
#define CONFIG_DRIVER_SMC911X_16_BIT
#define CONFIG_NET_MULTI
#define CONFIG_SMC911X 1
#define CONFIG_SMC911X_BASE 0x24000000
#define CONFIG_SMC911X_16_BIT
#define CONFIG_HOSTNAME bf548-ezkit
/* Uncomment next line to use fixed MAC address */
/* #define CONFIG_ETHADDR 02:80:ad:20:31:e8 */

View file

@ -69,9 +69,10 @@
* Network Settings
*/
#define ADI_CMDS_NETWORK 1
#define CONFIG_DRIVER_SMC911X 1
#define CONFIG_DRIVER_SMC911X_BASE 0x24000000
#define CONFIG_DRIVER_SMC911X_16_BIT
#define CONFIG_NET_MULTI
#define CONFIG_SMC911X 1
#define CONFIG_SMC911X_BASE 0x24000000
#define CONFIG_SMC911X_16_BIT
#define CONFIG_HOSTNAME cm-bf548
/* Uncomment next line to use fixed MAC address */
/* #define CONFIG_ETHADDR 02:80:ad:24:31:91 */

View file

@ -104,9 +104,10 @@
"prg_uboot=tftpboot 0x80000000 u-boot-imx31_litekit.bin; protect off all; erase 0xa00d0000 0xa01effff; cp.b 0x80000000 0xa00d0000 $(filesize)\0"
#define CONFIG_DRIVER_SMC911X 1
#define CONFIG_DRIVER_SMC911X_BASE (CS4_BASE + 0x00020000)
#define CONFIG_DRIVER_SMC911X_32_BIT 1
#define CONFIG_NET_MULTI
#define CONFIG_SMC911X 1
#define CONFIG_SMC911X_BASE (CS4_BASE + 0x00020000)
#define CONFIG_SMC911X_32_BIT 1
/*
* Miscellaneous configurable options

View file

@ -106,9 +106,10 @@
"prg_jffs2=tftpboot 0x80000000 $(jffs2); erase 0xa01c0000 0xa1ffffff; cp.b 0x80000000 0xa01c0000 $(filesize)\0"
#define CONFIG_DRIVER_SMC911X 1
#define CONFIG_DRIVER_SMC911X_BASE 0xa8000000
#define CONFIG_DRIVER_SMC911X_32_BIT 1
#define CONFIG_NET_MULTI
#define CONFIG_SMC911X 1
#define CONFIG_SMC911X_BASE 0xa8000000
#define CONFIG_SMC911X_32_BIT 1
/*
* Miscellaneous configurable options

View file

@ -106,9 +106,10 @@
"bootcmd_net=run bootargs_base bootargs_mtd bootargs_nfs; " \
"tftpboot 0x81000000 uImage-mx31; bootm\0"
#define CONFIG_DRIVER_SMC911X 1
#define CONFIG_DRIVER_SMC911X_BASE 0xB6000000
#define CONFIG_DRIVER_SMC911X_32_BIT 1
#define CONFIG_NET_MULTI
#define CONFIG_SMC911X 1
#define CONFIG_SMC911X_BASE 0xB6000000
#define CONFIG_SMC911X_32_BIT 1
/*
* Miscellaneous configurable options

View file

@ -302,9 +302,10 @@ extern unsigned int boot_flash_type;
*/
#if defined(CONFIG_CMD_NET)
#define CONFIG_DRIVER_SMC911X
#define CONFIG_DRIVER_SMC911X_32_BIT
#define CONFIG_DRIVER_SMC911X_BASE 0x2C000000
#define CONFIG_NET_MULTI
#define CONFIG_SMC911X
#define CONFIG_SMC911X_32_BIT
#define CONFIG_SMC911X_BASE 0x2C000000
#endif /* (CONFIG_CMD_NET) */

View file

@ -105,8 +105,9 @@
#define CONFIG_SYS_HZ (CONFIG_SYS_CLK_FREQ / CMT_CLK_DIVIDER)
/* Network interface */
#define CONFIG_DRIVER_SMC911X
#define CONFIG_DRIVER_SMC911X_16_BIT
#define CONFIG_DRIVER_SMC911X_BASE (0x24000000)
#define CONFIG_NET_MULTI
#define CONFIG_SMC911X
#define CONFIG_SMC911X_16_BIT
#define CONFIG_SMC911X_BASE (0x24000000)
#endif /* __RSK7203_H */

View file

@ -89,10 +89,11 @@
/*
* SMSC91C11x Network Card
*/
#define CONFIG_DRIVER_SMC911X
#define CONFIG_DRIVER_SMC911X_BASE 0x00000000
#define CONFIG_DRIVER_SMC911X_32_BIT
#define CONFIG_SMC911X
#define CONFIG_SMC911X_BASE 0x00000000
#define CONFIG_SMC911X_32_BIT
#define CONFIG_NET_RETRY_COUNT 20
#define CONFIG_NET_MULTI
#endif
/*
@ -342,7 +343,7 @@ int vct_gpio_get(int pin);
#undef CONFIG_CMD_TERMINAL
#undef CONFIG_CMD_USB
#undef CONFIG_DRIVER_SMC911X
#undef CONFIG_SMC911X
#undef CONFIG_SOFT_I2C
#undef CONFIG_SOURCE
#undef CONFIG_SYS_LONGHELP

View file

@ -331,8 +331,8 @@ extern IPaddr_t NetOurIP; /* Our IP addr (0 = unknown) */
extern IPaddr_t NetServerIP; /* Server IP addr (0 = unknown) */
extern volatile uchar * NetTxPacket; /* THE transmit packet */
extern volatile uchar * NetRxPackets[PKTBUFSRX];/* Receive packets */
extern volatile uchar * NetRxPkt; /* Current receive packet */
extern int NetRxPktLen; /* Current rx packet length */
extern volatile uchar * NetRxPacket; /* Current receive packet */
extern int NetRxPacketLen; /* Current rx packet length */
extern unsigned NetIPID; /* IP ID (counting) */
extern uchar NetBcastAddr[6]; /* Ethernet boardcast address */
extern uchar NetEtherNullAddr[6];
@ -361,6 +361,11 @@ typedef enum { BOOTP, RARP, ARP, TFTP, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP
/* from net/net.c */
extern char BootFile[128]; /* Boot File name */
#if defined(CONFIG_CMD_DNS)
extern char *NetDNSResolve; /* The host to resolve */
extern char *NetDNSenvvar; /* the env var to put the ip into */
#endif
#if defined(CONFIG_CMD_PING)
extern IPaddr_t NetPingIP; /* the ip address to ping */
#endif

View file

@ -50,6 +50,7 @@ int e1000_initialize(bd_t *bis);
int eepro100_initialize(bd_t *bis);
int eth_3com_initialize (bd_t * bis);
int fec_initialize (bd_t *bis);
int fecmxc_initialize (bd_t *bis);
int greth_initialize(bd_t *bis);
void gt6426x_eth_initialize(bd_t *bis);
int inca_switch_initialize(bd_t *bis);
@ -71,6 +72,7 @@ int rtl8139_initialize(bd_t *bis);
int rtl8169_initialize(bd_t *bis);
int scc_initialize(bd_t *bis);
int skge_initialize(bd_t *bis);
int smc911x_initialize(u8 dev_num, int base_addr);
int tsi108_eth_initialize(bd_t *bis);
int uec_initialize(int index);
int uec_standard_init(bd_t *bis);

View file

@ -27,13 +27,14 @@ include $(TOPDIR)/config.mk
LIB = $(obj)libnet.a
COBJS-y += net.o
COBJS-y += tftp.o
COBJS-y += bootp.o
COBJS-y += rarp.o
COBJS-$(CONFIG_CMD_DNS) += dns.o
COBJS-y += eth.o
COBJS-y += net.o
COBJS-y += nfs.o
COBJS-y += rarp.o
COBJS-$(CONFIG_CMD_SNTP) += sntp.o
COBJS-y += tftp.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)

View file

@ -124,7 +124,7 @@ static void BootpCopyNetParams(Bootp_t *bp)
NetCopyIP(&tmp_ip, &bp->bp_siaddr);
if (tmp_ip != 0)
NetCopyIP(&NetServerIP, &bp->bp_siaddr);
memcpy (NetServerEther, ((Ethernet_t *)NetRxPkt)->et_src, 6);
memcpy (NetServerEther, ((Ethernet_t *)NetRxPacket)->et_src, 6);
#endif
if (strlen(bp->bp_file) > 0)
copy_filename (BootFile, bp->bp_file, sizeof(BootFile));

211
net/dns.c Normal file
View file

@ -0,0 +1,211 @@
/*
* DNS support driver
*
* Copyright (c) 2008 Pieter Voorthuijsen <pieter.voorthuijsen@prodrive.nl>
* Copyright (c) 2009 Robin Getz <rgetz@blackfin.uclinux.org>
*
* This is a simple DNS implementation for U-Boot. It will use the first IP
* in the DNS response as NetServerIP. This can then be used for any other
* network related activities.
*
* The packet handling is partly based on TADNS, original copyrights
* follow below.
*
*/
/*
* Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
*
* "THE BEER-WARE LICENSE" (Revision 42):
* Sergey Lyubka wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return.
*/
#include <common.h>
#include <command.h>
#include <net.h>
#include "dns.h"
char *NetDNSResolve; /* The host to resolve */
char *NetDNSenvvar; /* The envvar to store the answer in */
static int DnsOurPort;
static void
DnsSend(void)
{
struct header *header;
int n, name_len;
uchar *p, *pkt;
const char *s;
const char *name;
enum dns_query_type qtype = DNS_A_RECORD;
name = NetDNSResolve;
pkt = p = (uchar *)(NetTxPacket + NetEthHdrSize() + IP_HDR_SIZE);
/* Prepare DNS packet header */
header = (struct header *) pkt;
header->tid = 1;
header->flags = htons(0x100); /* standard query */
header->nqueries = htons(1); /* Just one query */
header->nanswers = 0;
header->nauth = 0;
header->nother = 0;
/* Encode DNS name */
name_len = strlen(name);
p = (uchar *) &header->data; /* For encoding host name into packet */
do {
s = strchr(name, '.');
if (!s)
s = name + name_len;
n = s - name; /* Chunk length */
*p++ = n; /* Copy length */
memcpy(p, name, n); /* Copy chunk */
p += n;
if (*s == '.')
n++;
name += n;
name_len -= n;
} while (*s != '\0');
*p++ = 0; /* Mark end of host name */
*p++ = 0; /* Some servers require double null */
*p++ = (unsigned char) qtype; /* Query Type */
*p++ = 0;
*p++ = 1; /* Class: inet, 0x0001 */
n = p - pkt; /* Total packet length */
debug("Packet size %d\n", n);
DnsOurPort = random_port();
NetSendUDPPacket(NetServerEther, NetOurDNSIP, DNS_SERVICE_PORT,
DnsOurPort, n);
debug("DNS packet sent\n");
}
static void
DnsTimeout(void)
{
puts("Timeout\n");
NetState = NETLOOP_FAIL;
}
static void
DnsHandler(uchar *pkt, unsigned dest, unsigned src, unsigned len)
{
struct header *header;
const unsigned char *p, *e, *s;
u16 type, i;
int found, stop, dlen;
char IPStr[22];
IPaddr_t IPAddress;
short tmp;
debug("%s\n", __func__);
if (dest != DnsOurPort)
return;
for (i = 0; i < len; i += 4)
debug("0x%p - 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n",
pkt+i, pkt[i], pkt[i+1], pkt[i+2], pkt[i+3]);
/* We sent 1 query. We want to see more that 1 answer. */
header = (struct header *) pkt;
if (ntohs(header->nqueries) != 1)
return;
/* Received 0 answers */
if (header->nanswers == 0) {
puts("DNS server returned no answers\n");
NetState = NETLOOP_SUCCESS;
return;
}
/* Skip host name */
s = &header->data[0];
e = pkt + len;
for (p = s; p < e && *p != '\0'; p++)
continue;
/* We sent query class 1, query type 1 */
tmp = p[1] | (p[2] << 8);
if (&p[5] > e || ntohs(tmp) != DNS_A_RECORD) {
puts("DNS response was not A record\n");
NetState = NETLOOP_SUCCESS;
return;
}
/* Go to the first answer section */
p += 5;
/* Loop through the answers, we want A type answer */
for (found = stop = 0; !stop && &p[12] < e; ) {
/* Skip possible name in CNAME answer */
if (*p != 0xc0) {
while (*p && &p[12] < e)
p++;
p--;
}
debug("Name (Offset in header): %d\n", p[1]);
tmp = p[2] | (p[3] << 8);
type = ntohs(tmp);
debug("type = %d\n", type);
if (type == DNS_CNAME_RECORD) {
/* CNAME answer. shift to the next section */
debug("Found canonical name\n");
tmp = p[10] | (p[11] << 8);
dlen = ntohs(tmp);
debug("dlen = %d\n", dlen);
p += 12 + dlen;
} else if (type == DNS_A_RECORD) {
debug("Found A-record\n");
found = stop = 1;
} else {
debug("Unknown type\n");
stop = 1;
}
}
if (found && &p[12] < e) {
tmp = p[10] | (p[11] << 8);
dlen = ntohs(tmp);
p += 12;
memcpy(&IPAddress, p, 4);
if (p + dlen <= e) {
ip_to_string(IPAddress, IPStr);
printf("%s\n", IPStr);
if (NetDNSenvvar)
setenv(NetDNSenvvar, IPStr);
} else
puts("server responded with invalid IP number\n");
}
NetState = NETLOOP_SUCCESS;
}
void
DnsStart(void)
{
debug("%s\n", __func__);
NetSetTimeout(DNS_TIMEOUT, DnsTimeout);
NetSetHandler(DnsHandler);
DnsSend();
}

39
net/dns.h Normal file
View file

@ -0,0 +1,39 @@
/*
* (C) Masami Komiya <mkomiya@sonare.it> 2005
* Copyright 2009, Robin Getz <rgetz@blackfin.uclinux.org>
*
* 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, or (at
* your option) any later version.
*/
#ifndef __DNS_H__
#define __DNS_H__
#define DNS_SERVICE_PORT 53
#define DNS_TIMEOUT 10000UL
/* http://en.wikipedia.org/wiki/List_of_DNS_record_types */
enum dns_query_type {
DNS_A_RECORD = 0x01,
DNS_CNAME_RECORD = 0x05,
DNS_MX_RECORD = 0x0f,
};
/*
* DNS network packet
*/
struct header {
uint16_t tid; /* Transaction ID */
uint16_t flags; /* Flags */
uint16_t nqueries; /* Questions */
uint16_t nanswers; /* Answers */
uint16_t nauth; /* Authority PRs */
uint16_t nother; /* Other PRs */
unsigned char data[1]; /* Data, variable length */
};
extern void DnsStart(void); /* Begin DNS */
#endif

View file

@ -500,6 +500,8 @@ char *eth_get_name (void)
}
#elif defined(CONFIG_CMD_NET) && !defined(CONFIG_NET_MULTI)
#warning Ethernet driver is deprecated. Please update to use CONFIG_NET_MULTI
extern int at91rm9200_miiphy_initialize(bd_t *bis);
extern int mcf52x2_miiphy_initialize(bd_t *bis);
extern int ns7520_miiphy_initialize(bd_t *bis);

View file

@ -92,6 +92,9 @@
#if defined(CONFIG_CDP_VERSION)
#include <timestamp.h>
#endif
#if defined(CONFIG_CMD_DNS)
#include "dns.h"
#endif
#if defined(CONFIG_CMD_NET)
@ -139,8 +142,8 @@ uchar NetServerEther[6] = /* Boot server enet address */
{ 0, 0, 0, 0, 0, 0 };
IPaddr_t NetOurIP; /* Our IP addr (0 = unknown) */
IPaddr_t NetServerIP; /* Server IP addr (0 = unknown) */
volatile uchar *NetRxPkt; /* Current receive packet */
int NetRxPktLen; /* Current rx packet length */
volatile uchar *NetRxPacket; /* Current receive packet */
int NetRxPacketLen; /* Current rx packet length */
unsigned NetIPID; /* IP packet ID */
uchar NetBcastAddr[6] = /* Ethernet bcast address */
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@ -291,6 +294,9 @@ NetInitLoop(proto_t protocol)
NetServerIP = getenv_IPaddr ("serverip");
NetOurNativeVLAN = getenv_VLAN("nvlan");
NetOurVLAN = getenv_VLAN("vlan");
#if defined(CONFIG_CMD_DNS)
NetOurDNSIP = getenv_IPaddr("dnsip");
#endif
env_changed_id = env_id;
}
@ -388,17 +394,20 @@ restart:
#if defined(CONFIG_CMD_DHCP)
case DHCP:
BootpTry = 0;
NetOurIP = 0;
DhcpRequest(); /* Basically same as BOOTP */
break;
#endif
case BOOTP:
BootpTry = 0;
NetOurIP = 0;
BootpRequest ();
break;
case RARP:
RarpTry = 0;
NetOurIP = 0;
RarpRequest ();
break;
#if defined(CONFIG_CMD_PING)
@ -425,6 +434,11 @@ restart:
case SNTP:
SntpStart();
break;
#endif
#if defined(CONFIG_CMD_DNS)
case DNS:
DnsStart();
break;
#endif
default:
break;
@ -1122,8 +1136,8 @@ NetReceive(volatile uchar * inpkt, int len)
printf("packet received\n");
#endif
NetRxPkt = inpkt;
NetRxPktLen = len;
NetRxPacket = inpkt;
NetRxPacketLen = len;
et = (Ethernet_t *)inpkt;
/* too small packet? */
@ -1273,6 +1287,15 @@ NetReceive(volatile uchar * inpkt, int len)
/* are we waiting for a reply */
if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC)
break;
#ifdef CONFIG_KEEP_SERVERADDR
if (NetServerIP == NetArpWaitPacketIP) {
char buf[20];
sprintf(buf, "%pM", arp->ar_data);
setenv("serveraddr", buf);
}
#endif
#ifdef ET_DEBUG
printf("Got ARP REPLY, set server/gtwy eth addr (%pM)\n",
arp->ar_data);
@ -1518,6 +1541,14 @@ static int net_check_prereq (proto_t protocol)
}
goto common;
#endif
#if defined(CONFIG_CMD_DNS)
case DNS:
if (NetOurDNSIP == 0) {
puts("*** ERROR: DNS server address not given\n");
return 1;
}
goto common;
#endif
#if defined(CONFIG_CMD_NFS)
case NFS:
#endif
@ -1681,6 +1712,16 @@ void copy_filename (char *dst, char *src, int size)
#endif
#if defined(CONFIG_CMD_NFS) || defined(CONFIG_CMD_SNTP) || defined(CONFIG_CMD_DNS)
/*
* make port a little random, but use something trivial to compute
*/
unsigned int random_port(void)
{
return 1024 + (get_timer(0) % 0x8000);;
}
#endif
void ip_to_string (IPaddr_t x, char *s)
{
x = ntohl (x);