mirror of
https://github.com/u-boot/u-boot.git
synced 2024-11-26 05:34:30 +08:00
e2a53458a7
This is long over due. All but two net drivers have been converted, but those have now been dropped. The only thing left to do is actually delete all references to NET_MULTI and code that is compiled when that is not defined. So here we scrub the core code. Signed-off-by: Mike Frysinger <vapier@gentoo.org>
809 lines
22 KiB
C
809 lines
22 KiB
C
/**************************************************************************
|
|
Etherboot - BOOTP/TFTP Bootstrap Program
|
|
Skeleton NIC driver for Etherboot
|
|
***************************************************************************/
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
/*
|
|
* This file is a modified version from the Galileo polled mode
|
|
* network driver for the ethernet contained within the GT64260
|
|
* chip. It has been modified to fit into the U-Boot framework, from
|
|
* the original (etherboot) setup. Also, additional cleanup and features
|
|
* were added.
|
|
*
|
|
* - Josh Huber <huber@mclx.com>
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <malloc.h>
|
|
#include <galileo/gt64260R.h>
|
|
#include <galileo/core.h>
|
|
#include <asm/cache.h>
|
|
#include <miiphy.h>
|
|
#include <net.h>
|
|
#include <netdev.h>
|
|
|
|
#include "eth.h"
|
|
#include "eth_addrtbl.h"
|
|
|
|
#if defined(CONFIG_CMD_NET)
|
|
|
|
#define GT6426x_ETH_BUF_SIZE 1536
|
|
|
|
/* if you like verbose output, turn this on! */
|
|
#undef DEBUG
|
|
|
|
/* Restart autoneg if we detect link is up on phy init. */
|
|
|
|
/*
|
|
* The GT doc's say that after Rst is deasserted, and the PHY
|
|
* reports autoneg complete, it runs through its autoneg
|
|
* procedures. This doesn't seem to be the case for MII
|
|
* PHY's. To work around this check for link up && autoneg
|
|
* complete when initilizing the port. If they are both set,
|
|
* then restart PHY autoneg. Of course, it may be something
|
|
* completly different.
|
|
*/
|
|
#ifdef CONFIG_ETHER_PORT_MII
|
|
# define RESTART_AUTONEG
|
|
#endif
|
|
|
|
/* do this if you dont want to use snooping */
|
|
#define USE_SOFTWARE_CACHE_MANAGEMENT
|
|
|
|
#ifdef USE_SOFTWARE_CACHE_MANAGEMENT
|
|
#define FLUSH_DCACHE(a,b) if(dcache_status()){clean_dcache_range((u32)(a),(u32)(b));}
|
|
#define FLUSH_AND_INVALIDATE_DCACHE(a,b) if(dcache_status()){flush_dcache_range((u32)(a),(u32)(b));}
|
|
#define INVALIDATE_DCACHE(a,b) if(dcache_status()){invalidate_dcache_range((u32)(a),(u32)(b));}
|
|
#else
|
|
/* bummer - w/o flush, nothing works, even with snooping - FIXME */
|
|
/* #define FLUSH_DCACHE(a,b) */
|
|
#define FLUSH_DCACHE(a,b) if(dcache_status()){clean_dcache_range((u32)(a),(u32)(b));}
|
|
#define FLUSH_AND_INVALIDATE_DCACHE(a,b)
|
|
#define INVALIDATE_DCACHE(a,b)
|
|
#endif
|
|
struct eth_dev_s {
|
|
eth0_tx_desc_single *eth_tx_desc;
|
|
eth0_rx_desc_single *eth_rx_desc;
|
|
char *eth_tx_buffer;
|
|
char *eth_rx_buffer[NR];
|
|
int tdn, rdn;
|
|
int dev;
|
|
unsigned int reg_base;
|
|
};
|
|
|
|
|
|
#ifdef CONFIG_INTEL_LXT97X
|
|
/* for intel LXT972 */
|
|
static const char ether_port_phy_addr[3]={0,1,2};
|
|
#else
|
|
static const char ether_port_phy_addr[3]={4,5,6};
|
|
#endif
|
|
|
|
/* MII PHY access routines are common for all i/f, use gal_ent0 */
|
|
#define GT6426x_MII_DEVNAME "gal_enet0"
|
|
|
|
int gt6426x_miiphy_read(const char *devname, unsigned char phy,
|
|
unsigned char reg, unsigned short *val);
|
|
|
|
static inline unsigned short
|
|
miiphy_read_ret(unsigned short phy, unsigned short reg)
|
|
{
|
|
unsigned short val;
|
|
gt6426x_miiphy_read(GT6426x_MII_DEVNAME,phy,reg,&val);
|
|
return val;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
RESET - Reset adapter
|
|
***************************************************************************/
|
|
void
|
|
gt6426x_eth_reset(void *v)
|
|
{
|
|
/* we should do something here...
|
|
struct eth_device *wp = (struct eth_device *)v;
|
|
struct eth_dev_s *p = wp->priv;
|
|
*/
|
|
|
|
printf ("RESET\n");
|
|
/* put the card in its initial state */
|
|
}
|
|
|
|
static void gt6426x_handle_SMI(struct eth_dev_s *p, unsigned int icr)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("SMI interrupt: ");
|
|
|
|
if(icr&0x20000000) {
|
|
printf("SMI done\n");
|
|
}
|
|
#endif
|
|
|
|
if(icr&0x10000000) {
|
|
unsigned int psr;
|
|
psr=GTREGREAD(ETHERNET0_PORT_STATUS_REGISTER + p->reg_base);
|
|
#ifdef DEBUG
|
|
printf("PHY state change:\n"
|
|
" GT:%s:%s:%s:%s\n",
|
|
psr&1?"100":" 10",
|
|
psr&8?" Link":"nLink",
|
|
psr&2?"FD":"HD",
|
|
psr&4?" FC":"nFC");
|
|
|
|
#ifdef CONFIG_INTEL_LXT97X /* non-standard mii reg (intel lxt972a) */
|
|
{
|
|
unsigned short mii_11;
|
|
mii_11=miiphy_read_ret(ether_port_phy_addr[p->dev],0x11);
|
|
|
|
printf(" mii:%s:%s:%s:%s %s:%s %s\n",
|
|
mii_11&(1<<14)?"100":" 10",
|
|
mii_11&(1<<10)?" Link":"nLink",
|
|
mii_11&(1<<9)?"FD":"HD",
|
|
mii_11&(1<<4)?" FC":"nFC",
|
|
|
|
mii_11&(1<<7)?"ANc":"ANnc",
|
|
mii_11&(1<<8)?"AN":"Manual",
|
|
""
|
|
);
|
|
}
|
|
#endif /* CONFIG_INTEL_LXT97X */
|
|
#endif /* DEBUG */
|
|
}
|
|
}
|
|
|
|
static int
|
|
gt6426x_eth_receive(struct eth_dev_s *p,unsigned int icr)
|
|
{
|
|
int eth_len=0;
|
|
char *eth_data;
|
|
|
|
eth0_rx_desc_single *rx = &p->eth_rx_desc[(p->rdn)];
|
|
|
|
INVALIDATE_DCACHE((unsigned int)rx,(unsigned int)(rx+1));
|
|
|
|
if (rx->command_status & 0x80000000) {
|
|
return 0; /* No packet received */
|
|
}
|
|
|
|
eth_len = (unsigned int)
|
|
(rx->buff_size_byte_count) & 0x0000ffff;
|
|
eth_data = (char *) p->eth_rx_buffer[p->rdn];
|
|
|
|
#ifdef DEBUG
|
|
if (eth_len) {
|
|
printf ("%s: Recived %d byte Packet @ 0x%p\n",
|
|
__FUNCTION__, eth_len, eth_data);
|
|
}
|
|
#endif
|
|
/*
|
|
* packet is now in:
|
|
* eth0_rx_buffer[RDN_ETH0];
|
|
*/
|
|
|
|
/* let the upper layer handle the packet */
|
|
NetReceive ((uchar *)eth_data, eth_len);
|
|
|
|
rx->buff_size_byte_count = GT6426x_ETH_BUF_SIZE<<16;
|
|
|
|
|
|
/* GT96100 Owner */
|
|
rx->command_status = 0x80000000;
|
|
|
|
FLUSH_DCACHE((unsigned int)rx,(unsigned int)(rx+1));
|
|
|
|
p->rdn ++;
|
|
if (p->rdn == NR) {p->rdn = 0;}
|
|
|
|
sync();
|
|
|
|
/* Start Rx*/
|
|
GT_REG_WRITE (ETHERNET0_SDMA_COMMAND_REGISTER + p->reg_base, 0x00000080);
|
|
|
|
#ifdef DEBUG
|
|
{
|
|
int i;
|
|
for (i=0;i<12;i++) {
|
|
printf(" %02x", eth_data[i]);
|
|
}
|
|
}
|
|
printf(": %d bytes\n", eth_len);
|
|
#endif
|
|
INVALIDATE_DCACHE((unsigned int)eth_data,
|
|
(unsigned int)eth_data+eth_len);
|
|
return eth_len;
|
|
}
|
|
|
|
/**************************************************************************
|
|
POLL - look for an rx frame, handle other conditions
|
|
***************************************************************************/
|
|
int
|
|
gt6426x_eth_poll(void *v)
|
|
{
|
|
struct eth_device *wp = (struct eth_device *)v;
|
|
struct eth_dev_s *p = wp->priv;
|
|
unsigned int icr=GTREGREAD(ETHERNET0_INTERRUPT_CAUSE_REGISTER + p->reg_base);
|
|
|
|
if(icr) {
|
|
GT_REG_WRITE(ETHERNET0_INTERRUPT_CAUSE_REGISTER +p->reg_base, 0);
|
|
#ifdef DEBUG
|
|
printf("poll got ICR %08x\n", icr);
|
|
#endif
|
|
/* SMI done or PHY state change*/
|
|
if(icr&0x30000000) gt6426x_handle_SMI(p, icr);
|
|
}
|
|
/* always process. We aren't using RX interrupts */
|
|
return gt6426x_eth_receive(p, icr);
|
|
}
|
|
|
|
/**************************************************************************
|
|
TRANSMIT - Transmit a frame
|
|
***************************************************************************/
|
|
int
|
|
gt6426x_eth_transmit(void *v, volatile char *p, unsigned int s)
|
|
{
|
|
struct eth_device *wp = (struct eth_device *)v;
|
|
struct eth_dev_s *dev = (struct eth_dev_s *)wp->priv;
|
|
#ifdef DEBUG
|
|
unsigned int old_command_stat,old_psr;
|
|
#endif
|
|
eth0_tx_desc_single *tx = &dev->eth_tx_desc[dev->tdn];
|
|
|
|
/* wait for tx to be ready */
|
|
INVALIDATE_DCACHE((unsigned int)tx,(unsigned int)(tx+1));
|
|
while (tx->command_status & 0x80000000) {
|
|
int i;
|
|
for(i=0;i<1000;i++);
|
|
INVALIDATE_DCACHE((unsigned int)tx,(unsigned int)(tx+1));
|
|
}
|
|
|
|
GT_REG_WRITE (ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER0 + dev->reg_base,
|
|
(unsigned int)tx);
|
|
|
|
#ifdef DEBUG
|
|
printf("copying to tx_buffer [%p], length %x, desc = %p\n",
|
|
dev->eth_tx_buffer, s, dev->eth_tx_desc);
|
|
#endif
|
|
memcpy(dev->eth_tx_buffer, (char *) p, s);
|
|
|
|
tx->buff_pointer = (uchar *)dev->eth_tx_buffer;
|
|
tx->bytecount_reserved = ((__u16)s) << 16;
|
|
|
|
/* 31 - own
|
|
* 22 - gencrc
|
|
* 18:16 - pad, last, first */
|
|
tx->command_status = (1<<31) | (1<<22) | (7<<16);
|
|
#if 0
|
|
/* FEr #18 */
|
|
tx->next_desc = NULL;
|
|
#else
|
|
tx->next_desc =
|
|
(struct eth0_tx_desc_struct *)
|
|
&dev->eth_tx_desc[(dev->tdn+1)%NT].bytecount_reserved;
|
|
|
|
/* cpu owned */
|
|
dev->eth_tx_desc[(dev->tdn+1)%NT].command_status = (7<<16); /* pad, last, first */
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
old_command_stat=tx->command_status,
|
|
old_psr=GTREGREAD(ETHERNET0_PORT_STATUS_REGISTER + dev->reg_base);
|
|
#endif
|
|
|
|
FLUSH_DCACHE((unsigned int)tx,
|
|
(unsigned int)&dev->eth_tx_desc[(dev->tdn+2)%NT]);
|
|
|
|
FLUSH_DCACHE((unsigned int)dev->eth_tx_buffer,(unsigned int)dev->eth_tx_buffer+s);
|
|
|
|
GT_REG_WRITE(ETHERNET0_SDMA_COMMAND_REGISTER + dev->reg_base, 0x01000000);
|
|
|
|
#ifdef DEBUG
|
|
{
|
|
unsigned int command_stat=0;
|
|
printf("cmd_stat: %08x PSR: %08x\n", old_command_stat, old_psr);
|
|
/* wait for tx to be ready */
|
|
do {
|
|
unsigned int psr=GTREGREAD(ETHERNET0_PORT_STATUS_REGISTER + dev->reg_base);
|
|
command_stat=tx->command_status;
|
|
if(command_stat!=old_command_stat || psr !=old_psr) {
|
|
printf("cmd_stat: %08x PSR: %08x\n", command_stat, psr);
|
|
old_command_stat = command_stat;
|
|
old_psr = psr;
|
|
}
|
|
/* gt6426x_eth0_poll(); */
|
|
} while (command_stat & 0x80000000);
|
|
|
|
printf("sent %d byte frame\n", s);
|
|
|
|
if((command_stat & (3<<15)) == 3) {
|
|
printf("frame had error (stat=%08x)\n", command_stat);
|
|
}
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************************************
|
|
DISABLE - Turn off ethernet interface
|
|
***************************************************************************/
|
|
void
|
|
gt6426x_eth_disable(void *v)
|
|
{
|
|
struct eth_device *wp = (struct eth_device *)v;
|
|
struct eth_dev_s *p = (struct eth_dev_s *)wp->priv;
|
|
|
|
GT_REG_WRITE(ETHERNET0_SDMA_COMMAND_REGISTER + p->reg_base, 0x80008000);
|
|
}
|
|
|
|
/**************************************************************************
|
|
MII utilities - write: write to an MII register via SMI
|
|
***************************************************************************/
|
|
int
|
|
gt6426x_miiphy_write(const char *devname, unsigned char phy,
|
|
unsigned char reg, unsigned short data)
|
|
{
|
|
unsigned int temp= (reg<<21) | (phy<<16) | data;
|
|
|
|
while(GTREGREAD(ETHERNET_SMI_REGISTER) & (1<<28)); /* wait for !Busy */
|
|
|
|
GT_REG_WRITE(ETHERNET_SMI_REGISTER, temp);
|
|
return 0;
|
|
}
|
|
|
|
/**************************************************************************
|
|
MII utilities - read: read from an MII register via SMI
|
|
***************************************************************************/
|
|
int
|
|
gt6426x_miiphy_read(const char *devname, unsigned char phy,
|
|
unsigned char reg, unsigned short *val)
|
|
{
|
|
unsigned int temp= (reg<<21) | (phy<<16) | 1<<26;
|
|
|
|
while(GTREGREAD(ETHERNET_SMI_REGISTER) & (1<<28)); /* wait for !Busy */
|
|
|
|
GT_REG_WRITE(ETHERNET_SMI_REGISTER, temp);
|
|
|
|
while(1) {
|
|
temp=GTREGREAD(ETHERNET_SMI_REGISTER);
|
|
if(temp & (1<<27)) break; /* wait for ReadValid */
|
|
}
|
|
*val = temp & 0xffff;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
/**************************************************************************
|
|
MII utilities - dump mii registers
|
|
***************************************************************************/
|
|
static void
|
|
gt6426x_dump_mii(bd_t *bis, unsigned short phy)
|
|
{
|
|
printf("mii reg 0 - 3: %04x %04x %04x %04x\n",
|
|
miiphy_read_ret(phy, 0x0),
|
|
miiphy_read_ret(phy, 0x1),
|
|
miiphy_read_ret(phy, 0x2),
|
|
miiphy_read_ret(phy, 0x3)
|
|
);
|
|
printf(" 4 - 7: %04x %04x %04x %04x\n",
|
|
miiphy_read_ret(phy, 0x4),
|
|
miiphy_read_ret(phy, 0x5),
|
|
miiphy_read_ret(phy, 0x6),
|
|
miiphy_read_ret(phy, 0x7)
|
|
);
|
|
printf(" 8: %04x\n",
|
|
miiphy_read_ret(phy, 0x8)
|
|
);
|
|
printf(" 16-19: %04x %04x %04x %04x\n",
|
|
miiphy_read_ret(phy, 0x10),
|
|
miiphy_read_ret(phy, 0x11),
|
|
miiphy_read_ret(phy, 0x12),
|
|
miiphy_read_ret(phy, 0x13)
|
|
);
|
|
printf(" 20,30: %04x %04x\n",
|
|
miiphy_read_ret(phy, 20),
|
|
miiphy_read_ret(phy, 30)
|
|
);
|
|
}
|
|
#endif
|
|
|
|
#ifdef RESTART_AUTONEG
|
|
|
|
/* If link is up && autoneg compleate, and if
|
|
* GT and PHY disagree about link capabilitys,
|
|
* restart autoneg - something screwy with FD/HD
|
|
* unless we do this. */
|
|
static void
|
|
check_phy_state(struct eth_dev_s *p)
|
|
{
|
|
int bmsr = miiphy_read_ret(ether_port_phy_addr[p->dev], MII_BMSR);
|
|
int psr = GTREGREAD(ETHERNET0_PORT_STATUS_REGISTER + p->reg_base);
|
|
|
|
if ((psr & 1<<3) && (bmsr & BMSR_LSTATUS)) {
|
|
int nego = miiphy_read_ret(ether_port_phy_addr[p->dev], MII_ADVERTISE) &
|
|
miiphy_read_ret(ether_port_phy_addr[p->dev], MII_LPA);
|
|
int want;
|
|
|
|
if (nego & LPA_100FULL) {
|
|
want = 0x3;
|
|
printf("MII: 100Base-TX, Full Duplex\n");
|
|
} else if (nego & LPA_100HALF) {
|
|
want = 0x1;
|
|
printf("MII: 100Base-TX, Half Duplex\n");
|
|
} else if (nego & LPA_10FULL) {
|
|
want = 0x2;
|
|
printf("MII: 10Base-T, Full Duplex\n");
|
|
} else if (nego & LPA_10HALF) {
|
|
want = 0x0;
|
|
printf("MII: 10Base-T, Half Duplex\n");
|
|
} else {
|
|
printf("MII: Unknown link-foo! %x\n", nego);
|
|
return;
|
|
}
|
|
|
|
if ((psr & 0x3) != want) {
|
|
printf("MII: GT thinks %x, PHY thinks %x, restarting autoneg..\n",
|
|
psr & 0x3, want);
|
|
miiphy_write(GT6426x_MII_DEVNAME,ether_port_phy_addr[p->dev],0,
|
|
miiphy_read_ret(ether_port_phy_addr[p->dev],0) | (1<<9));
|
|
udelay(10000); /* the EVB's GT takes a while to notice phy
|
|
went down and up */
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/**************************************************************************
|
|
PROBE - Look for an adapter, this routine's visible to the outside
|
|
***************************************************************************/
|
|
int
|
|
gt6426x_eth_probe(void *v, bd_t *bis)
|
|
{
|
|
struct eth_device *wp = (struct eth_device *)v;
|
|
struct eth_dev_s *p = (struct eth_dev_s *)wp->priv;
|
|
int dev = p->dev;
|
|
unsigned int reg_base = p->reg_base;
|
|
unsigned long temp;
|
|
int i;
|
|
|
|
if (( dev < 0 ) || ( dev >= GAL_ETH_DEVS ))
|
|
{ /* This should never happen */
|
|
printf("%s: Invalid device %d\n", __FUNCTION__, dev );
|
|
return 0;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
printf ("%s: initializing %s\n", __FUNCTION__, wp->name );
|
|
printf ("\nCOMM_CONTROL = %08x , COMM_CONF = %08x\n",
|
|
GTREGREAD(COMM_UNIT_ARBITER_CONTROL),
|
|
GTREGREAD(COMM_UNIT_ARBITER_CONFIGURATION_REGISTER));
|
|
#endif
|
|
|
|
/* clear MIB counters */
|
|
for(i=0;i<255; i++)
|
|
temp=GTREGREAD(ETHERNET0_MIB_COUNTER_BASE + reg_base +i);
|
|
|
|
#ifdef CONFIG_INTEL_LXT97X
|
|
/* for intel LXT972 */
|
|
|
|
/* led 1: 0x1=txact
|
|
led 2: 0xc=link/rxact
|
|
led 3: 0x2=rxact (N/C)
|
|
strch: 0,2=30 ms, enable */
|
|
miiphy_write(GT6426x_MII_DEVNAME,ether_port_phy_addr[p->dev], 20, 0x1c22);
|
|
|
|
/* 2.7ns port rise time */
|
|
/*miiphy_write(ether_port_phy_addr[p->dev], 30, 0x0<<10); */
|
|
#else
|
|
/* already set up in mpsc.c */
|
|
/*GT_REG_WRITE(MAIN_ROUTING_REGISTER, 0x7ffe38); / b400 */
|
|
|
|
/* already set up in sdram_init.S... */
|
|
/* MPSC0, MPSC1, RMII */
|
|
/*GT_REG_WRITE(SERIAL_PORT_MULTIPLEX, 0x1102); / f010 */
|
|
#endif
|
|
GT_REG_WRITE(ETHERNET_PHY_ADDRESS_REGISTER,
|
|
ether_port_phy_addr[0] |
|
|
(ether_port_phy_addr[1]<<5) |
|
|
(ether_port_phy_addr[2]<<10)); /* 2000 */
|
|
|
|
/* 13:12 - 10: 4x64bit burst (cache line size = 32 bytes)
|
|
* 9 - 1: RIFB - interrupt on frame boundaries only
|
|
* 6:7 - 00: big endian rx and tx
|
|
* 5:2 - 1111: 15 retries */
|
|
GT_REG_WRITE(ETHERNET0_SDMA_CONFIGURATION_REGISTER + reg_base,
|
|
(2<<12) | (1<<9) | (0xf<<2) ); /* 2440 */
|
|
|
|
#ifndef USE_SOFTWARE_CACHE_MANAGEMENT
|
|
/* enable rx/tx desc/buffer cache snoop */
|
|
GT_REG_READ(ETHERNET_0_ADDRESS_CONTROL_LOW + dev*0x20,
|
|
&temp); /* f200 */
|
|
temp|= (1<<6)| (1<<14)| (1<<22)| (1<<30);
|
|
GT_REG_WRITE(ETHERNET_0_ADDRESS_CONTROL_LOW + dev*0x20,
|
|
temp);
|
|
#endif
|
|
|
|
/* 31 28 27 24 23 20 19 16
|
|
* 0000 0000 0000 0000 [0004]
|
|
* 15 12 11 8 7 4 3 0
|
|
* 1000 1101 0000 0000 [4d00]
|
|
* 20 - 0=MII 1=RMII
|
|
* 19 - 0=speed autoneg
|
|
* 15:14 - framesize 1536 (GT6426x_ETH_BUF_SIZE)
|
|
* 11 - no force link pass
|
|
* 10 - 1=disable fctl autoneg
|
|
* 8 - override prio ?? */
|
|
temp = 0x00004d00;
|
|
#ifndef CONFIG_ETHER_PORT_MII
|
|
temp |= (1<<20); /* RMII */
|
|
#endif
|
|
/* set En */
|
|
GT_REG_WRITE(ETHERNET0_PORT_CONFIGURATION_EXTEND_REGISTER + reg_base,
|
|
temp); /* 2408 */
|
|
|
|
/* hardcode E1 also? */
|
|
/* -- according to dox, this is safer due to extra pulldowns? */
|
|
if (dev<2) {
|
|
GT_REG_WRITE(ETHERNET0_PORT_CONFIGURATION_EXTEND_REGISTER + (dev+1) * 0x400,
|
|
temp); /* 2408 */
|
|
}
|
|
|
|
/* wake up MAC */ /* 2400 */
|
|
GT_REG_READ(ETHERNET0_PORT_CONFIGURATION_REGISTER + reg_base, &temp);
|
|
temp |= (1<<7); /* enable port */
|
|
#ifdef CONFIG_GT_USE_MAC_HASH_TABLE
|
|
temp |= (1<<12); /* hash size 1/2k */
|
|
#else
|
|
temp |= 1; /* promisc */
|
|
#endif
|
|
GT_REG_WRITE(ETHERNET0_PORT_CONFIGURATION_REGISTER + reg_base, temp);
|
|
/* 2400 */
|
|
|
|
#ifdef RESTART_AUTONEG
|
|
check_phy_state(p);
|
|
#endif
|
|
|
|
printf("%s: Waiting for link up..\n", wp->name);
|
|
temp = 10 * 1000;
|
|
/* wait for link back up */
|
|
while(!(GTREGREAD(ETHERNET0_PORT_STATUS_REGISTER + reg_base) & 8)
|
|
&& (--temp > 0)){
|
|
udelay(1000); /* wait 1 ms */
|
|
}
|
|
if ( temp == 0) {
|
|
printf("%s: Failed!\n", wp->name);
|
|
return (0);
|
|
}
|
|
|
|
printf("%s: OK!\n", wp->name);
|
|
|
|
p->tdn = 0;
|
|
p->rdn = 0;
|
|
p->eth_tx_desc[p->tdn].command_status = 0;
|
|
|
|
/* Initialize Rx Side */
|
|
for (temp = 0; temp < NR; temp++) {
|
|
p->eth_rx_desc[temp].buff_pointer = (uchar *)p->eth_rx_buffer[temp];
|
|
p->eth_rx_desc[temp].buff_size_byte_count = GT6426x_ETH_BUF_SIZE<<16;
|
|
|
|
/* GT96100 Owner */
|
|
p->eth_rx_desc[temp].command_status = 0x80000000;
|
|
p->eth_rx_desc[temp].next_desc =
|
|
(struct eth0_rx_desc_struct *)
|
|
&p->eth_rx_desc[(temp+1)%NR].buff_size_byte_count;
|
|
}
|
|
|
|
FLUSH_DCACHE((unsigned int)&p->eth_tx_desc[0],
|
|
(unsigned int)&p->eth_tx_desc[NR]);
|
|
FLUSH_DCACHE((unsigned int)&p->eth_rx_desc[0],
|
|
(unsigned int)&p->eth_rx_desc[NR]);
|
|
|
|
GT_REG_WRITE(ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER0 + reg_base,
|
|
(unsigned int) p->eth_tx_desc);
|
|
GT_REG_WRITE(ETHERNET0_FIRST_RX_DESCRIPTOR_POINTER0 + reg_base,
|
|
(unsigned int) p->eth_rx_desc);
|
|
GT_REG_WRITE(ETHERNET0_CURRENT_RX_DESCRIPTOR_POINTER0 + reg_base,
|
|
(unsigned int) p->eth_rx_desc);
|
|
|
|
#ifdef DEBUG
|
|
printf ("\nRx descriptor pointer is %08x %08x\n",
|
|
GTREGREAD(ETHERNET0_FIRST_RX_DESCRIPTOR_POINTER0 + reg_base),
|
|
GTREGREAD(ETHERNET0_CURRENT_RX_DESCRIPTOR_POINTER0 + reg_base));
|
|
printf ("\n\n%08x %08x\n",
|
|
(unsigned int)p->eth_rx_desc,p->eth_rx_desc[0].command_status);
|
|
|
|
printf ("Descriptor dump:\n");
|
|
printf ("cmd status: %08x\n",p->eth_rx_desc[0].command_status);
|
|
printf ("byte_count: %08x\n",p->eth_rx_desc[0].buff_size_byte_count);
|
|
printf ("buff_ptr: %08x\n",(unsigned int)p->eth_rx_desc[0].buff_pointer);
|
|
printf ("next_desc: %08x\n\n",(unsigned int)p->eth_rx_desc[0].next_desc);
|
|
printf ("%08x\n",*(unsigned int *) ((unsigned int)p->eth_rx_desc + 0x0));
|
|
printf ("%08x\n",*(unsigned int *) ((unsigned int)p->eth_rx_desc + 0x4));
|
|
printf ("%08x\n",*(unsigned int *) ((unsigned int)p->eth_rx_desc + 0x8));
|
|
printf ("%08x\n\n",
|
|
*(unsigned int *) ((unsigned int)p->eth_rx_desc + 0xc));
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
gt6426x_dump_mii(bis,ether_port_phy_addr[p->dev]);
|
|
#endif
|
|
|
|
#ifdef CONFIG_GT_USE_MAC_HASH_TABLE
|
|
{
|
|
unsigned int hashtable_base;
|
|
u8 *b = (u8 *)(wp->enetaddr);
|
|
u32 macH, macL;
|
|
|
|
/* twist the MAC up into the way the discovery wants it */
|
|
macH= (b[0]<<8) | b[1];
|
|
macL= (b[2]<<24) | (b[3]<<16) | (b[4]<<8) | b[5];
|
|
|
|
/* mode 0, size 0x800 */
|
|
hashtable_base =initAddressTable(dev,0,1);
|
|
|
|
if(!hashtable_base) {
|
|
printf("initAddressTable failed\n");
|
|
return 0;
|
|
}
|
|
|
|
addAddressTableEntry(dev, macH, macL, 1, 0);
|
|
GT_REG_WRITE(ETHERNET0_HASH_TABLE_POINTER_REGISTER + reg_base,
|
|
hashtable_base);
|
|
}
|
|
#endif
|
|
|
|
/* Start Rx*/
|
|
GT_REG_WRITE(ETHERNET0_SDMA_COMMAND_REGISTER + reg_base, 0x00000080);
|
|
printf("%s: gt6426x eth device %d init success \n", wp->name, dev );
|
|
return 1;
|
|
}
|
|
|
|
/* enter all the galileo ethernet devs into MULTI-BOOT */
|
|
void
|
|
gt6426x_eth_initialize(bd_t *bis)
|
|
{
|
|
struct eth_device *dev;
|
|
struct eth_dev_s *p;
|
|
int devnum, x, temp;
|
|
char *s, *e, buf[64];
|
|
|
|
#ifdef DEBUG
|
|
printf( "\n%s\n", __FUNCTION );
|
|
#endif
|
|
|
|
for (devnum = 0; devnum < GAL_ETH_DEVS; devnum++) {
|
|
dev = calloc(sizeof(*dev), 1);
|
|
if (!dev) {
|
|
printf( "%s: gal_enet%d allocation failure, %s\n",
|
|
__FUNCTION__, devnum, "eth_device structure");
|
|
return;
|
|
}
|
|
|
|
/* must be less than NAMESIZE (16) */
|
|
sprintf(dev->name, "gal_enet%d", devnum);
|
|
|
|
#ifdef DEBUG
|
|
printf( "Initializing %s\n", dev->name );
|
|
#endif
|
|
|
|
/* Extract the MAC address from the environment */
|
|
switch (devnum)
|
|
{
|
|
case 0: s = "ethaddr"; break;
|
|
#if (GAL_ETH_DEVS > 1)
|
|
case 1: s = "eth1addr"; break;
|
|
#endif
|
|
#if (GAL_ETH_DEVS > 2)
|
|
case 2: s = "eth2addr"; break;
|
|
#endif
|
|
default: /* this should never happen */
|
|
printf( "%s: Invalid device number %d\n",
|
|
__FUNCTION__, devnum );
|
|
return;
|
|
}
|
|
|
|
temp = getenv_f(s, buf, sizeof(buf));
|
|
s = (temp > 0) ? buf : NULL;
|
|
|
|
#ifdef DEBUG
|
|
printf ("Setting MAC %d to %s\n", devnum, s );
|
|
#endif
|
|
for (x = 0; x < 6; ++x) {
|
|
dev->enetaddr[x] = s ? simple_strtoul(s, &e, 16) : 0;
|
|
if (s)
|
|
s = (*e) ? e+1 : e;
|
|
}
|
|
|
|
dev->init = (void*)gt6426x_eth_probe;
|
|
dev->halt = (void*)gt6426x_eth_reset;
|
|
dev->send = (void*)gt6426x_eth_transmit;
|
|
dev->recv = (void*)gt6426x_eth_poll;
|
|
|
|
p = calloc( sizeof(*p), 1 );
|
|
dev->priv = (void*)p;
|
|
if (!p)
|
|
{
|
|
printf( "%s: %s allocation failure, %s\n",
|
|
__FUNCTION__, dev->name, "Private Device Structure");
|
|
free(dev);
|
|
return;
|
|
}
|
|
|
|
p->dev = devnum;
|
|
p->tdn=0;
|
|
p->rdn=0;
|
|
p->reg_base = devnum * ETHERNET_PORTS_DIFFERENCE_OFFSETS;
|
|
|
|
p->eth_tx_desc =
|
|
(eth0_tx_desc_single *)
|
|
(((unsigned int) malloc(sizeof (eth0_tx_desc_single) *
|
|
(NT+1)) & 0xfffffff0) + 0x10);
|
|
if (!p)
|
|
{
|
|
printf( "%s: %s allocation failure, %s\n",
|
|
__FUNCTION__, dev->name, "Tx Descriptor");
|
|
free(dev);
|
|
return;
|
|
}
|
|
|
|
p->eth_rx_desc =
|
|
(eth0_rx_desc_single *)
|
|
(((unsigned int) malloc(sizeof (eth0_rx_desc_single) *
|
|
(NR+1)) & 0xfffffff0) + 0x10);
|
|
if (!p->eth_rx_desc)
|
|
{
|
|
printf( "%s: %s allocation failure, %s\n",
|
|
__FUNCTION__, dev->name, "Rx Descriptor");
|
|
free(dev);
|
|
free(p);
|
|
return;
|
|
}
|
|
|
|
p->eth_tx_buffer =
|
|
(char *) (((unsigned int) malloc(GT6426x_ETH_BUF_SIZE) & 0xfffffff0) + 0x10);
|
|
if (!p->eth_tx_buffer)
|
|
{
|
|
printf( "%s: %s allocation failure, %s\n",
|
|
__FUNCTION__, dev->name, "Tx Bufffer");
|
|
free(dev);
|
|
free(p);
|
|
free(p->eth_rx_desc);
|
|
return;
|
|
}
|
|
|
|
for (temp = 0 ; temp < NR ; temp ++) {
|
|
p->eth_rx_buffer[temp] =
|
|
(char *)
|
|
(((unsigned int) malloc(GT6426x_ETH_BUF_SIZE) & 0xfffffff0) + 0x10);
|
|
if (!p->eth_rx_buffer[temp])
|
|
{
|
|
printf( "%s: %s allocation failure, %s\n",
|
|
__FUNCTION__, dev->name, "Rx Buffers");
|
|
free(dev);
|
|
free(p);
|
|
free(p->eth_tx_buffer);
|
|
free(p->eth_rx_desc);
|
|
free(p->eth_tx_desc);
|
|
while (temp >= 0)
|
|
free(p->eth_rx_buffer[--temp]);
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
eth_register(dev);
|
|
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
|
|
miiphy_register(dev->name,
|
|
gt6426x_miiphy_read, gt6426x_miiphy_write);
|
|
#endif
|
|
}
|
|
|
|
}
|
|
#endif
|