mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-11 15:37:23 +00:00
Merge branch 'master' of git://git.denx.de/u-boot-net
This commit is contained in:
commit
4fb799aeaf
45 changed files with 1943 additions and 243 deletions
5
README
5
README
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
64
doc/README.dns
Normal 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
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
742
drivers/net/fec_mxc.c
Normal 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
304
drivers/net/fec_mxc.h
Normal 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 */
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) */
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
211
net/dns.c
Normal 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
39
net/dns.h
Normal 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
|
|
@ -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);
|
||||
|
|
49
net/net.c
49
net/net.c
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue