📄 ethernet_cs8900a.c
字号:
//////////////////////////////////////////////////////////////////////////////////// Copyright(c) 2001 Intrinsyc Software Inc. All rights reserved.//// Module name://// ethernet_cs8900a.c//// Description://// Driver for the Crystal CS8900a ethernet chip.//// Author://// Mike Kirkland//// Created://// October 2001////////////////////////////////////////////////////////////////////////////////////We want failures to get to the user#define _DEBUG#define _DEBUG_FAIL#include <ethernet_cs8900a.h>#include <ethernet.h>#include <string.h>#include <util.h>#include <net.h>#include <types.h>#include <timer.h>#include <c_main.h>#include <messages.h>#include <debug.h>////////////////////////////////////////////////////////////////////////////////// readcs// PURPOSE: Reads data from a specified packetpage register on the CS89x0// PARAMS: (IN) u16 csreg - register to read from// RETURNS: u16 value of specified register////////////////////////////////////////////////////////////////////////////////inline static u16readcs(u16 csreg){ *(volatile u16 *)(BASE_ADDR + ADDRESS_PORT) = csreg; return (*(volatile u16 *)(BASE_ADDR + DATA_PORT));}////////////////////////////////////////////////////////////////////////////////// writecs// PURPOSE: Writes a u16 to a specified packetpage register on the CS89x0// PARAMS: (IN) u16 csreg - register to write to// (IN) u16 lhv - data to write to register// RETURNS: Nothing.////////////////////////////////////////////////////////////////////////////////inline static voidwritecs(u16 csreg, u16 lhv){ *(volatile u16 *)(BASE_ADDR + ADDRESS_PORT) = csreg; *(volatile u16 *)(BASE_ADDR + DATA_PORT) = lhv;}////////////////////////////////////////////////////////////////////////////////// notbusy// PURPOSE: Wait for Crystal chip to stop being busy// PARAMS: None.// RETURNS: None.////////////////////////////////////////////////////////////////////////////////static voidnotbusy(void){ while(readcs(SSR) & SSR_BUSY) { ; //do nothing }}////////////////////////////////////////////////////////////////////////////////// probe_cs8900a// PURPOSE: Look for signs of a CS8900A at the given address// PARAMS: (OUT) u16 * address to check// RETURNS: 1 for success, 0 for failure.// NOTE: This function is safe to call even right after a reset////////////////////////////////////////////////////////////////////////////////static intprobe_cs8900a(char *address){/* // The data sheet only says this is valid after a hard reset if(((*(volatile u16 *)(address + ADDRESS_PORT)) & SCAN_MASK) != SCAN_SIG) { return 0; }*/ // We are allowed to read this register even during a reset // (so says Cirrus AN205) if((readcs(SSR) & REG_NUMB_MASK) != 0x16) { return 0; } return 1;}////////////////////////////////////////////////////////////////////////////////// toggle_sbhe// PURPOSE: Toggle the /SBHE line on the CS8900// PARAMS: None.// RETURNS: None.// NOTES: This is really ugly, as we have to access PCMCIA I/O space in order// to control A0, which is connected to /SBHE.////////////////////////////////////////////////////////////////////////////////static voidtoggle_sbhe(void){ u8 volatile temp; temp = *(u8 volatile *)(PCMCIA_SOCKET_0_IO_BASE + 1); temp = *(u8 volatile *)(PCMCIA_SOCKET_0_IO_BASE + 0); temp = *(u8 volatile *)(PCMCIA_SOCKET_0_IO_BASE + 1); temp = *(u8 volatile *)(PCMCIA_SOCKET_0_IO_BASE + 0);}////////////////////////////////////////////////////////////////////////////////// init_ethernet// PURPOSE: Initializes the cs8900a ethernet chip.// PARAMS: (OUT) u16 * to return the MAC address.// RETURNS: 1 for success, 0 for failure.////////////////////////////////////////////////////////////////////////////////intinit_ethernet(u16 *macaddr){ u16 mac[3]; DEBUG_4("Initializing CS8900\r\n"); // Toggle /SBHE before we try probing the chip toggle_sbhe(); // Look for signs of a CS8900A before we start doing things to it if (!probe_cs8900a((char *)BASE_ADDR)) { error_print(CS_NOTFOUND_ERROR); DEBUG_1("(at address %x)\r\n", BASE_ADDR); return 0; } itc_printf("CS8900A found at 0x%x\r\n", BASE_ADDR); // Reset CS8900 chip writecs(SCR, readcs(SCR) | POWER_ON_RESET); // Must delay for some time here or else the chip might never come alive. // This seem to happen with certain invalid contents of the EEPROM. udelay(10000); // Must toggle /SBHE again after reset toggle_sbhe(); //DEBUG_4("Waiting for CS8900..."); // Wait for chip to finish resetting (takes up to 10 ms) while(!(readcs(SSR) & SSR_INITD)) { ; //do nothing } DEBUG_4("CS8900 reset\r\n"); if(readcs(CS8900ID) != CS89x0_ISA_ID) { error_print(CS_ISAID_ERROR); return 0; } if((readcs(PROD_ID) & PROD_ID_MASK) != CS8900ID) { error_print(CS_NOTCS_ERROR); return 0; } if(((*(volatile u16 *)(BASE_ADDR + TX_CMD_PRT)) & REG_NUMB_MASK) != REG_NUMB_TX_CMD) { error_print(CS_NOTX_ERROR); return 0; } //check the Line Status Register to see if cabling is plugged in. // NOTE: this might not be reliable unless we wait a bit first if((readcs(LSR) & LSR_OK) == 0) { DEBUG_1("Link disconnected.\r\n"); } else { DEBUG_2("Link connected\r\n"); } if (!read_mac_ethernet(mac, 0)) { error_print(CS_NOMAC_ERROR); return 0; } macaddr[0] = mac[0]; macaddr[1] = mac[1]; macaddr[2] = mac[2]; //write MAC to the address reg //this is already done if the EEPROM uses the reset configuration block //but won't be if the MAC address was written with an old version of I-Boot writecs(IAR, mac[0]); writecs(IAR+2, mac[1]); writecs(IAR+4, mac[2]); //Take interrupt and DMA lines out of high impedance state writecs(INR, 0); writecs(DCR, 0); //IO channel ready on writecs(BCR, (readcs(BCR) | BCR_IO_CHN_ON)); //set Rx Config Register to defaults writecs(RX_CONFIG_REG, RX_DEFAULT); //set Tx Config Register to defaults writecs(TX_CONFIG_REG, TX_DEFAULT); //set Buffer Config Register to defaults writecs(BUFFER_CONFIG_REG, BUF_CONFIG_DEFAULT); //set up acceptance filter writecs(RCR, (RCR_RX_IA | RCR_RX_BROADCAST | RCR_RX_MULTICAST | RCR_RX_OK)); //enable frame Rx and Tx writecs(LCR, (readcs(LCR) | LCR_SERIAL_RX_ON | LCR_SERIAL_TX_ON)); writecs(TX_CMD_REQ, TX_AFTER_ALL | TX_PAD); writecs(TX_LENGTH, 0); while(!(readcs(BSR) & READY_FOR_TX_NOW)); readcs(TX_EVENT); return 1;}////////////////////////////////////////////////////////////////////////////////// tx_packet_ethernet// PURPOSE: Transmits a packet.// PARAMS: (IN) u16 * to return the MAC address.// RETURNS: 1 for success, 0 for failure.////////////////////////////////////////////////////////////////////////////////inttx_packet_ethernet(u8 *data, u16 size){ int i = 0; u16 temp = 0; u32 time = get_time_timer(); //initiate tx sequence writecs(TX_CMD_REQ, TX_AFTER_ALL | TX_PAD); writecs(TX_LENGTH, size); //wait for the chip to free room in it's internal buffer while(!(readcs(BSR) & READY_FOR_TX_NOW)) { if(time < get_time_timer() - NET_TIMEOUT) { return 0; } } //give the packet to the chip for(i = 0; i < (size / sizeof(u16));i++) { *(volatile u16 *)(BASE_ADDR + TX_FRAME_PORT) = *(u16 *)data; data += sizeof(u16); } //if we are sending a packet of uneven size, send the last byte. if(size % sizeof(u16)) { *(volatile u16 *)(BASE_ADDR + TX_FRAME_PORT) = *data; } //check for tx errors temp = readcs(TX_EVENT); if(temp & (TX_EXCESSIVE_COL | TX_JABBER | TX_LOST_CRS | TX_OUT_OF_WINDOW | TX_SQE_ERROR)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -