📄 dc2114x.c
字号:
/* * (C) Copyright 2001 * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com * * See file CREDITS for list of people who contributed to this * project. * * 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 <ppcboot.h>#include <net.h>/* phy seed setup */#define AUTO 99#define _100BASET 100#define _10BASET 10#define HALF 22#define FULL 44/* phy register offsets */#define PHY_BMCR 0x00#define PHY_BMSR 0x01#define PHY_PHY1DR1 0x02#define PHY_PHYIDR2 0x03#define PHY_ANAR 0x04#define PHY_ANLPAR 0x05#define PHY_ANER 0x06#define PHY_ANNPTR 0x07#define PHY_PHYSTS 0x10#define PHY_MIPSCR 0x11#define PHY_MIPGSR 0x12#define PHY_DCR 0x13#define PHY_FCSCR 0x14#define PHY_RECR 0x15#define PHY_PCSR 0x16#define PHY_LBR 0x17#define PHY_10BTSCR 0x18#define PHY_PHYCTRL 0x19/*phy ANLPAR */#define PHY_ANLPAR_NP 0x8000#define PHY_ANLPAR_ACK 0x4000#define PHY_ANLPAR_RF 0x2000#define PHY_ANLPAR_T4 0x0200#define PHY_ANLPAR_TXFD 0x0100#define PHY_ANLPAR_TX 0x0080#define PHY_ANLPAR_10FD 0x0040#define PHY_ANLPAR_10 0x0020#define PHY_ANLPAR_100 0x0380 /* we can run at 100 *//* PCI Registers. */#define PCI_VENDOR_ID 0x00#define PCI_COMMAND 0x04#define PCI_CLASS_REVISION 0x08#define PCI_LATENCY_TIMER 0x0d#define PCI_BASE_ADDRESS_0 0x10#define PCI_BASE_ADDRESS_1 0x14#define PCI_BASE_ADDRESS_2 0x18#define PCI_CFDA_PSM 0x43#define PCI_COMMAND_IO 0x1#define PCI_COMMAND_MEM 0x2#define PCI_COMMAND_MASTER 0x4#define CFRV_RN 0x000000f0 /* Revision Number */#define CBIO_MASK -128#define WAKEUP 0x00 /* Power Saving Wakeup */#define SLEEP 0x80 /* Power Saving Sleep Mode */#define DC2114x_VID 0x1011 /* DC2114[23] Manufacturer */#define DC2114x_DID 0x1900 /* Unique Device ID # */#define DC2114x_BRK 0x0020 /* CFRV break between DC21142 & DC21143 */#define DC21142 (DC2114x_DID | 0x0010)#define DC21143 (DC2114x_DID | 0x0030)#define is_DC2114x ((vendor == DC2114x_VID) && (device == DC2114x_DID))/* Ethernet chip registers. */#define DE4X5_BMR iobase + 0x000 /* Bus Mode Register */#define DE4X5_TPD iobase + 0x008 /* Transmit Poll Demand Reg */#define DE4X5_RRBA iobase + 0x018 /* RX Ring Base Address Reg */#define DE4X5_TRBA iobase + 0x020 /* TX Ring Base Address Reg */#define DE4X5_STS iobase + 0x028 /* Status Register */#define DE4X5_OMR iobase + 0x030 /* Operation Mode Register */#define DE4X5_SICR iobase + 0x068 /* SIA Connectivity Register */#define DE4X5_APROM iobase + 0x048 /* Ethernet Address PROM *//* Register bits. */#define BMR_SWR 0x00000001 /* Software Reset */#define STS_TS 0x00700000 /* Transmit Process State */#define STS_RS 0x000e0000 /* Receive Process State */#define OMR_ST 0x00002000 /* Start/Stop Transmission Command */#define OMR_SR 0x00000002 /* Start/Stop Receive */#define OMR_PS 0x00040000 /* Port Select */#define OMR_SDP 0x02000000 /* SD Polarity - MUST BE ASSERTED */#define OMR_PM 0x00000080 /* Pass All Multicast *//* Descriptor bits. */#define R_OWN 0x80000000 /* Own Bit */#define RD_RER 0x02000000 /* Receive End Of Ring */#define RD_LS 0x00000100 /* Last Descriptor */#define RD_ES 0x00008000 /* Error Summary */#define TD_TER 0x02000000 /* Transmit End Of Ring */#define T_OWN 0x80000000 /* Own Bit */#define TD_LS 0x40000000 /* Last Segment */#define TD_FS 0x20000000 /* First Segment */#define TD_ES 0x00008000 /* Error Summary */#define TD_SET 0x08000000 /* Setup Packet */#define SROM_HWADD 0x0014 /* Hardware Address offset in SROM */#define SROM_RD 0x00004000 /* Read from Boot ROM */#define SROM_SR 0x00000800 /* Select Serial ROM when set */#define DT_IN 0x00000004 /* Serial Data In */#define DT_CLK 0x00000002 /* Serial ROM Clock */#define DT_CS 0x00000001 /* Serial ROM Chip Select */#define POLL_DEMAND 1#define RESET_DE4X5 {\ int i;\ i=inl(DE4X5_BMR);\ udelay(1000);\ outl(i | BMR_SWR, DE4X5_BMR);\ udelay(1000);\ outl(i, DE4X5_BMR);\ udelay(1000);\ for (i=0;i<5;i++) {inl(DE4X5_BMR); udelay(10000);}\ udelay(1000);\}#define START_DE4X5 {\ s32 omr; \ omr = inl(DE4X5_OMR);\ omr |= OMR_ST | OMR_SR;\ outl(omr, DE4X5_OMR); /* Enable the TX and/or RX */\}#define STOP_DE4X5 {\ s32 omr; \ omr = inl(DE4X5_OMR);\ omr &= ~(OMR_ST|OMR_SR);\ outl(omr, DE4X5_OMR); /* Disable the TX and/or RX */ \}#define NUM_RX_DESC PKTBUFSRX#define NUM_TX_DESC 1 /* Number of TX descriptors */#define RX_BUFF_SZ PKTSIZE_ALIGN#define TOUT_LOOP 1000000#define SETUP_FRAME_LEN 192#define ETH_ALEN 6struct de4x5_desc { volatile s32 status; u32 des1; u32 buf; u32 next;};static struct de4x5_desc rx_ring[NUM_RX_DESC]; /* RX descriptor ring */static struct de4x5_desc tx_ring[NUM_TX_DESC]; /* TX descriptor ring */static int rx_new; /* RX descriptor ring pointer */static int tx_new; /* TX descriptor ring pointer */static char rxRingSize;static char txRingSize;static u_long iobase;unsigned int PCI_Read_CFG_Reg(int BusDevFunc, int Reg, int Width);int PCI_Write_CFG_Reg(int BusDevFunc, int Reg, unsigned int Value, int Width);static void send_setup_frame(bd_t * bis);static void check_hw_addr(bd_t * bis);static short srom_rd(u_long address, u_char offset);static void srom_latch(u_int command, u_long address);static void srom_command(u_int command, u_long address);static void srom_address(u_int command, u_long address, u_char offset);static short srom_data(u_int command, u_long address);static void sendto_srom(u_int command, u_long addr);static int getfrom_srom(u_long addr);static void updateSRom(bd_t *bis);static unsigned long dcCsrRead(unsigned long, int);static int inl(u_long addr){ return le32_to_cpu(*(volatile u_long *)(addr));}static void outl (int command, u_long addr){ *(volatile u_long *)(addr) = cpu_to_le32(command);}int eth_init(bd_t *bis){ int i, status = 0; int vendor, device, l; int cfrv; unsigned char timer; unsigned long bmcr;#if 0 // test-only { int val; for (l=0; l<6; l++) { printf("%02x: ", l*0x10); for (i=0; i<4; i++) { val = PCI_Read_CFG_Reg(CFG_ETH_DEV_FN, l*16+i*4, 4); printf("%08x ", val); } printf("\n"); } printf("\n"); }#endif l = PCI_Read_CFG_Reg(CFG_ETH_DEV_FN, PCI_CLASS_REVISION, 4); l >>= 8; if (l != 0x00020000) { printf("Error: Can not find an ethernet card on the PCI bus %d " "in slot %d\n", CFG_ETH_DEV_FN >> 16, (CFG_ETH_DEV_FN & 0xFFFF) >> 11); goto Done; } vendor = PCI_Read_CFG_Reg(CFG_ETH_DEV_FN, PCI_VENDOR_ID, 4); device = (vendor >> 16) & 0xffff; vendor = vendor & 0xffff; device = device << 8; if (! is_DC2114x) { printf("Error: The chip is not DC2114x.\n"); goto Done; } /* Get the chip configuration revision register. */ cfrv = PCI_Read_CFG_Reg(CFG_ETH_DEV_FN, PCI_CLASS_REVISION, 4); device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143); if (device != DC21143) { printf("Error: The chip is not DC21143.\n"); goto Done; } status = PCI_Read_CFG_Reg(CFG_ETH_DEV_FN, PCI_COMMAND, 2); status |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEM; PCI_Write_CFG_Reg(CFG_ETH_DEV_FN, PCI_COMMAND, status, 2); /* Check the latency timer for values >= 0x60. */ timer = PCI_Read_CFG_Reg(CFG_ETH_DEV_FN, PCI_LATENCY_TIMER, 1); if (timer < 0x60) { PCI_Write_CFG_Reg(CFG_ETH_DEV_FN, PCI_LATENCY_TIMER, 0x60, 1); } /* Set I/O base register. */ PCI_Write_CFG_Reg(CFG_ETH_DEV_FN, PCI_BASE_ADDRESS_0, CFG_ETH_IOBASE, 4); iobase = PCI_Read_CFG_Reg(CFG_ETH_DEV_FN, PCI_BASE_ADDRESS_0, 4); PCI_Write_CFG_Reg(CFG_ETH_DEV_FN, PCI_BASE_ADDRESS_1, CFG_ETH_IOBASE, 4); iobase = PCI_Read_CFG_Reg(CFG_ETH_DEV_FN, PCI_BASE_ADDRESS_1, 4); if (iobase == 0xffffffff) { printf("Error: Can not set I/O base register.\n"); goto Done; } iobase &= CBIO_MASK; iobase += 0xc0000000; // test-only /* Ensure we're not sleeping. */ PCI_Write_CFG_Reg(CFG_ETH_DEV_FN, PCI_CFDA_PSM, WAKEUP, 1); udelay(10 * 1000); check_hw_addr(bis); RESET_DE4X5; if ((inl(DE4X5_STS) & (STS_TS | STS_RS)) != 0) { printf("Error: Can not reset ethernet controller.\n"); goto Done; } outl(OMR_SDP | OMR_PS | OMR_PM, DE4X5_OMR); for (i = 0; i < NUM_RX_DESC; i++) { rx_ring[i].status = cpu_to_le32(R_OWN); rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ); rx_ring[i].buf = cpu_to_le32((u_long)NetRxPackets[i]); rx_ring[i].next = 0; } for (i=0; i < NUM_TX_DESC; i++) { tx_ring[i].status = 0; tx_ring[i].des1 = 0; tx_ring[i].buf = 0; tx_ring[i].next = 0; } rxRingSize = NUM_RX_DESC; txRingSize = NUM_TX_DESC; /* Write the end of list marker to the descriptor lists. */ rx_ring[rxRingSize - 1].des1 |= cpu_to_le32(RD_RER); tx_ring[txRingSize - 1].des1 |= cpu_to_le32(TD_TER); /* Tell the adapter where the TX/RX rings are located. */ outl((u_long)&rx_ring, DE4X5_RRBA); outl((u_long)&tx_ring, DE4X5_TRBA); START_DE4X5; tx_new = 0; rx_new = 0; bmcr = dcCsrRead(0, PHY_ANLPAR); printf("ENET Speed is %d Mbps - %s duplex connection\n", ((bmcr & PHY_ANLPAR_100) != 0) ? 100 : 10, ((bmcr & (PHY_ANLPAR_10FD | PHY_ANLPAR_TXFD)) != 0) ? "FULL" : "HALF"); send_setup_frame(bis); Done: return 0;}int eth_send(volatile void *packet, int length){ int status = 0; int i; if (length <= 0) { printf("eth: bad packet size: %d\n", length); goto out; } for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) { if (i >= TOUT_LOOP) { printf("eth: tx error buffer not ready\n"); goto out; } } tx_ring[tx_new].buf = cpu_to_le32((u_long)packet); tx_ring[tx_new].des1 = cpu_to_le32(TD_TER | TD_LS | TD_FS | length); tx_ring[tx_new].status = cpu_to_le32(T_OWN); outl(POLL_DEMAND, DE4X5_TPD); for(i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) { if (i >= TOUT_LOOP) { printf("eth: tx buffer not ready\n"); goto out; } }#if 0 // test-only if (le32_to_cpu(tx_ring[tx_new].status) & TD_ES) { printf("TX error status = 0x%08X\n", le32_to_cpu(tx_ring[tx_new].status)); status++; }#endif out: return status;}int eth_rx(void){ s32 status; int length = 0; for ( ; ; ) { status = (s32)le32_to_cpu(rx_ring[rx_new].status); if (status & R_OWN) { break; } if (status & RD_LS) { /* Valid frame status. */ if (status & RD_ES) { /* There was an error. */ printf("RX error status = 0x%08X\n", status); } else { /* A valid frame received. */ length = (le32_to_cpu(rx_ring[rx_new].status) >> 16); /* Pass the packet up to the protocol * layers. */ NetReceive(NetRxPackets[rx_new], length - 4); } /* Change buffer ownership for this frame, back * to the adapter. */ rx_ring[rx_new].status = cpu_to_le32(R_OWN); } /* Update entry information. */ rx_new = (++rx_new) % rxRingSize; } return length;}void eth_halt(void){#if 1 if (iobase != CFG_ETH_IOBASE) { /* Ethernet has not been initialized yet. */ return; } STOP_DE4X5; outl(0, DE4X5_SICR); PCI_Write_CFG_Reg(CFG_ETH_DEV_FN, PCI_CFDA_PSM, SLEEP, 1);#endif}static void check_hw_addr(bd_t *bis){ unsigned char hw_addr[ETH_ALEN]; u_short tmp, *p = (short *)(&hw_addr[0]); int i, j = 0; for (i = 0; i < (ETH_ALEN >> 1); i++) { tmp = srom_rd(DE4X5_APROM, (SROM_HWADD >> 1) + i); *p = le16_to_cpu(tmp); j += *p++; } if ((j == 0) || (j == 0x2fffd)) { printf("Warning: can't read HW address from SROM.\n"); if ((bis->bi_enetaddr[0] != 0) || (bis->bi_enetaddr[1] != 0) || (bis->bi_enetaddr[2] != 0) || (bis->bi_enetaddr[3] != 0) || (bis->bi_enetaddr[4] != 0) || (bis->bi_enetaddr[5] != 0)) { printf("Updating SROM data - please wait...\n"); updateSRom(bis); } goto Done; } for (i = 0; i < ETH_ALEN; i++) { if (hw_addr[i] != bis->bi_enetaddr[i]) { printf("Warning: HW addresses don't match:\n"); printf("Address in SROM is " "%02X:%02X:%02X:%02X:%02X:%02X\n", hw_addr[0], hw_addr[1], hw_addr[2], hw_addr[3], hw_addr[4], hw_addr[5]); printf("Address used by ppcboot is " "%02X:%02X:%02X:%02X:%02X:%02X\n", bis->bi_enetaddr[0], bis->bi_enetaddr[1], bis->bi_enetaddr[2], bis->bi_enetaddr[3],
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -