📄 eth.c
字号:
/**************************************************************************Etherboot - BOOTP/TFTP Bootstrap ProgramSkeleton 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 "eth.h"#include "eth_addrtbl.h"#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI)#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)#endifstruct 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};#elsestatic const char ether_port_phy_addr[3]={4,5,6};#endifstatic inline unsigned shortmiiphy_read_ret(unsigned short phy, unsigned short reg){ unsigned short val; miiphy_read(phy,reg,&val); return val;}/**************************************************************************RESET - Reset adapter***************************************************************************/voidgt6426x_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 intgt6426x_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 (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***************************************************************************/intgt6426x_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***************************************************************************/intgt6426x_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 = 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***************************************************************************/voidgt6426x_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***************************************************************************/intmiiphy_write(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***************************************************************************/intmiiphy_read(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 voidgt6426x_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),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -