From: Stefan E. <se...@us...> - 2004-02-25 11:00:25
|
Update of /cvsroot/blob/blob/src/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21459/src/lib Modified Files: ether-smc9196.c ether.c Added Files: ether-cs8900.c Log Message: CS8900 ethernet driver --- NEW FILE: ether-cs8900.c --- /* * cs8900.c driver for the cs8900 on the Sharp LH79520 and LH7A400 * Evaluation Boards. * * Copyright (C) 2001 SHARP MICROELECTRONICS OF THE AMERICAS, INC. * CAMAS, WA * * Portions Copyright (C) 2002 Lineo. * * 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 * * References: * (1) ARM Isis Technical Reference Manual, System on Chip Group, * ARM SC063-TRM-0001-C * */ #ifdef HAVE_CONFIG_H #include <blob/config.h> #endif #include <blob/types.h> #include <blob/command.h> #include <blob/errno.h> #include <blob/init.h> #include <blob/main.h> #include <blob/util.h> #include <net/ether.h> #include <net/cs8900.h> #if defined(LH79520) #include <blob/lh79520_smc.h> #include <blob/lh79520_cpld.h> #endif extern int xprintf( const char *format, ...); #define printf xprintf //#define DEBUG 1 #if 0 // List of addresses for each read and write port #if defined(LH79520) u16 * const cs8900_port_addr [8] = {(u16 *) 0x4C000000, (u16 *) 0x4C000004, (u16 *) 0x4C000008, (u16 *) 0x4C00000C, (u16 *) 0x4C000010, (u16 *) 0x4C000014, (u16 *) 0x4C000018, (u16 *) 0x4C00001C}; #elif defined(LH7A400) u16 * const cs8900_port_addr [8] = {(u16 *) 0x30000000, (u16 *) 0x30000004, (u16 *) 0x30000008, (u16 *) 0x3000000C, (u16 *) 0x30000010, (u16 *) 0x30000014, (u16 *) 0x30000018, (u16 *) 0x3000001C}; #endif #endif static u16 *cs8900_port_addr[8]; /* * Write data to the specified port. */ static inline void cs8900_write_port( u16 port_id, u16 data) { *cs8900_port_addr[port_id] = data; } /* * Reads data from the specified port. */ static inline u16 cs8900_read_port( u16 port_id) { return( *cs8900_port_addr [port_id]); } /* * Set the PP pointer register and optionally enable the * autoincrement function */ static void cs8900_set_pp_addr( void *address, int autoinc) { u16 addr = (u16) ((int) address); if( autoinc) { // Set autoincrement bit in PacketPage pointer value addr |= 0x8000; } #if DEBUG // DDD printf( "Setting ppptr address to 0x%x (%d)\n", (int) addr, autoinc); #endif *cs8900_port_addr [ppptr] = addr; } /* * Read data from the current PP register address. */ static u16 cs8900_read_pp_data( void) { #if DEBUG u16 data; data = *cs8900_port_addr [pd0]; printf( "Data read from port = %x\n", (int) data); return data; #else return (*cs8900_port_addr [pd0]); #endif } /* * Write data to the current PP register address. */ static inline void cs8900_write_pp_data( u16 data) { *cs8900_port_addr [pd0] = data; #if DEBUG printf( "Data written to port = %x\n", (int) data); #endif } /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */ /* * This is a pointer to a memory mapped PacketPage structure at * address 0x0. Don't try to access the pointer at that address or * the system may crash. However, the offsets used for the port I/O * mapping functions can be used with the address attribute. */ static cs8900_pp_t *cs8900_pp_data = (void *) 0x0; /* * read the MAC address from EEPROM */ static void cs8900_get_address( u8 eaddr[6]) { u16 enet_vals [3]; int i; // Read the ethernet address from the controller cs8900_set_pp_addr( &cs8900_pp_data->filter_regs.enet_address, 1); enet_vals [0] = cs8900_read_pp_data(); enet_vals [1] = cs8900_read_pp_data(); enet_vals [2] = cs8900_read_pp_data(); // Convert ethernet address to 6 bytes for( i = 0 ; i < 6; i = i + 2) { eaddr [i ] = enet_vals [i / 2] & 0xFF; eaddr [i + 1] = (enet_vals [i / 2] & 0xFF00) >> 8; } } /* * Initialize the CS8900 * return 0 on success, -ENONIC otherwise. */ static int cs8900_init( void) { u16 volatile temp; int i; for (i=0;i<8;i++) cs8900_port_addr[i]= cs8900_ether_driver.base + 4*(i+1); /* make sure we can talk to the cs8900 */ cs8900_set_pp_addr( &cs8900_pp_data->bus_regs.chip_id_h, 0); if( (temp = cs8900_read_pp_data()) != CS8900_CHIP_ID) { printf( "Can't find CS8900 NIC. Got ID=0x%x\n", temp); return -ENONIC; } cs8900_set_pp_addr( &cs8900_pp_data->stco_regs.reg16_selfst, 0); // Before starting with the configuration, disable the receiver // and transmitter cs8900_set_pp_addr( &cs8900_pp_data->stco_regs.reg13_linectl, 0); cs8900_write_pp_data( 0); // Disable ethernet controller DMA cs8900_set_pp_addr( &cs8900_pp_data->bus_regs.dma_channel, 0); cs8900_write_pp_data( DMA_NONE); // Set memory base address to 0 (not used) cs8900_set_pp_addr( &cs8900_pp_data->bus_regs.mem_base_h, 1); cs8900_write_pp_data( 0); // High half of word cs8900_write_pp_data( 0); // Low half of word // Set boot PROM address and size to 0 (not used) cs8900_set_pp_addr( &cs8900_pp_data->bus_regs.boot_pr_addr_h, 1); cs8900_write_pp_data( 0); // High half of boot PROM address cs8900_write_pp_data( 0); // Low half of boot PROM address cs8900_write_pp_data( 0); // High half of boot PROM mask (size) cs8900_write_pp_data( 0); // Low half of boot PROM mask (size) // Configure the receiver // No DMA // Interrupt on good RX frames only // No support for short or long frames // Do not include CRC in buffer cs8900_set_pp_addr( &cs8900_pp_data->stco_regs.reg3_rxcfg, 0); cs8900_write_pp_data( RXOKIE); // Setup receiver control // Accept no other frames besides IA frames // Accept on valid RX frames // Do not accept short or long frames // Do not accept frames with a CRC error cs8900_set_pp_addr( &cs8900_pp_data->stco_regs.reg5_rxctl, 0); cs8900_write_pp_data( RRXCTL | RXOKA | INDIVIDUALA); // Configure the transmitter // Interrupt generated on completion of TX interrupt cs8900_set_pp_addr( &cs8900_pp_data->stco_regs.reg7_txcfg, 0); cs8900_write_pp_data( TXOKIE); // Configure the buffers // Interrupt ONLY when ready to transfer a new packet cs8900_set_pp_addr( &cs8900_pp_data->stco_regs.regb_bufcfg, 0); // Setup for polling mode cs8900_write_pp_data( 0); // Configure self control // No support for hardware power modes // Status LEDS are active cs8900_set_pp_addr( &cs8900_pp_data->stco_regs.reg15_selfctl, 0); cs8900_write_pp_data( 0); // Configure bus control // Disable memory mode and IOCHRDY // Enable interrupts cs8900_set_pp_addr( &cs8900_pp_data->stco_regs.reg17_busctl, 0); cs8900_write_pp_data( 0); // Configure test control // No test modes are enabled cs8900_set_pp_addr( &cs8900_pp_data->stco_regs.reg19_testctl, 0); cs8900_write_pp_data( 0); // Clear hash filter, not used cs8900_set_pp_addr( &cs8900_pp_data->filter_regs.hash_filter, 1); cs8900_write_pp_data( 0); cs8900_write_pp_data( 0); cs8900_write_pp_data( 0); cs8900_write_pp_data( 0); // Get local copy of ethernet controller address. This should // of been loaded from the EEPROM at reset //FIXME: cs8900_get_address( blob_status.hwaddress); #ifdef BLOB_DEBUG printf( "CS8900 found. MAC="); for( i=0; i<5; i++) printf( "%x:", blob_status.hwaddress[i]); printf( "%x\n", blob_status.hwaddress[i]); #endif // Setup interrupt line INTR0 as the active interrupt. The // ethernet interrupt is active high and must be configued // active high via the interrupt configuration in the RCPC. cs8900_set_pp_addr( &cs8900_pp_data->bus_regs.int_num, 0); cs8900_write_pp_data( INTR0); // Clear any pending interrupts and all messages from controller while( cs8900_read_port( isq) != 0) ; // Enable receiver and transmitter cs8900_set_pp_addr( &cs8900_pp_data->stco_regs.reg13_linectl, 0); cs8900_write_pp_data( SERRXON | SERTXON); // Enable receiver for broadcast and our packets cs8900_set_pp_addr( &cs8900_pp_data->stco_regs.reg5_rxctl, 0); cs8900_write_pp_data( RXOKA | INDIVIDUALA | BROADCASTA); /* we're ready to go */ return 0; } /* * read a packet from the net, and put it in buf * * return the number of bytes read, or 0 if no data available. */ static int cs8900_read( void *buf, int size) { int u16Count, byteCount; u16 *port; if( (cs8900_read_port(isq) & RXOK) != 0) { // Last message received was valid, process it // Read the length of the message in bytes cs8900_set_pp_addr( &cs8900_pp_data->frame_regs.rxlen, 1); byteCount = cs8900_read_pp_data(); if( byteCount) { // If the byte count is odd, add a single byte to it (needed // to make sure all 'bytes' are read from a half-word interface) // Convert the count to a word count u16Count = (byteCount + (byteCount & 0x1)) / 2; #if DEBUG printf( "readether size=%d bytes=%d u16Count=%d\n", size, byteCount, u16Count); #endif // Copy the packet from the controller to the buffer port = cs8900_port_addr[pd0]; while( u16Count-- ) *((u16 *)buf)++ = *port; } return byteCount; } return 0; } /* * Send the packet described by (buf, length) * * return 1 on success. */ static int cs8900_write( void *buf, int length) { int u16Count; u16 *port; /* * plug our source address in the packet, and ship it */ memcpy( (char *)buf + 6, blob_status.hwaddress, 6); #if DEBUG printf( "send_packet() length=%d\n", length); #endif /* Write the TX command word to the controller */ cs8900_write_port( txcmd, TX_START_ALL); /* Write the size of the packet to the controller (in bytes) */ length += length & 1; cs8900_write_port( txlen, (u16) length); u16Count = length / 2; port = cs8900_port_addr[txd0]; /* Wait for TX buffer space to become available */ cs8900_set_pp_addr( &cs8900_pp_data->stco_regs.reg18_busst, 0); while( (cs8900_read_pp_data() & RDY4TXNOW) == 0) ; /* Controller is ready for data now so move it */ while( u16Count--) *port = *((u16 *)buf)++; return 1; } /* * we're about to leave blob, so clean things up. */ static void cs8900_exit( void) { /* * the kernel seems to expect the PacketPage pointer to be here, * so we'll accomadate. */ cs8900_set_pp_addr( &cs8900_pp_data->bus_regs.chip_id_h, 0); } /* export network driver */ ether_driver_t cs8900_ether_driver = { .name = "CS8900", .init = cs8900_init, .rcv = cs8900_read, .snd = cs8900_write, .set_addr = NULL, .get_addr = cs8900_get_address, .base = CS8900_BASE, }; Index: ether-smc9196.c =================================================================== RCS file: /cvsroot/blob/blob/src/lib/ether-smc9196.c,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- ether-smc9196.c 17 Feb 2004 10:59:29 -0000 1.3 +++ ether-smc9196.c 25 Feb 2004 10:53:19 -0000 1.4 @@ -679,6 +679,7 @@ /* export ethernet driver */ ether_driver_t smc9196_ether_driver = { + .name = "SMC9196", .init = smc_init, .rcv = readether, .snd = writeether, Index: ether.c =================================================================== RCS file: /cvsroot/blob/blob/src/lib/ether.c,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- ether.c 11 Nov 2003 12:45:48 -0000 1.5 +++ ether.c 25 Feb 2004 10:53:19 -0000 1.6 @@ -82,6 +82,7 @@ int ether_get_addr(u8 hw_addr[6]) { if (!ether_driver) return -EINVAL; + if (!ether_driver->get_addr) return -EINVAL; return ether_driver->get_addr(hw_addr); } @@ -89,6 +90,7 @@ int ether_set_addr(u8 hw_addr[6]) { if (!ether_driver) return -EINVAL; + if (!ether_driver->set_addr) return -EINVAL; memcpy(hwaddress, hw_addr, 6); return ether_driver->set_addr(hw_addr); } |