📄 cs8900_enet_if_driver.c
字号:
/*****************************************************************************
* $Workfile: CS8900_enet_if_driver.c $
* $Revision: 1.1 $
* $Author: MaysR $
* $Date: Aug 29 2002 08:57:52 $
*
* Project: General ethernet driver for CS8900A
*
* Description: This file contains functions to perform the following:
* Initialization of the CS8900A ethernet controller
* Responds to ethernet interrupts
* Provides read data to another process
* Initiates transfer of data packets
*
* References: CS8900 Datasheet
*
* Notes: The user must provide the 3 functions listed as extern's
* at the top of this file. These functions are platform
* dependent.
*
* Revision History:
* $Log: //smaicnt2/pvcs/VM/CHIPS/archives/LH7A400/Ethernet/Drivers/CS8900_enet_if_driver.c-arc $
*
* Rev 1.1 Aug 29 2002 08:57:52 MaysR
* Corrected parameter types for set IRQ and set DMA functions.
*
* Rev 1.0 Aug 27 2002 11:41:04 MaysR
* Initial revision.
*
*
* SHARP MICROELECTRONICS OF THE AMERICAS MAKES NO REPRESENTATION
* OR WARRANTIES WITH RESPECT TO THE PERFORMANCE OF THIS SOFTWARE,
* AND SPECIFICALLY DISCLAIMS ANY RESPONSIBILITY FOR ANY DAMAGES,
* SPECIAL OR CONSEQUENTIAL, CONNECTED WITH THE USE OF THIS SOFTWARE.
*
* SHARP MICROELECTRONICS OF THE AMERICAS PROVIDES THIS SOFTWARE SOLELY
* FOR THE PURPOSE OF SOFTWARE DEVELOPMENT INCORPORATING THE USE OF A
* SHARP MICROCONTROLLER OR SYSTEM-ON-CHIP PRODUCT. USE OF THIS SOURCE
* FILE IMPLIES ACCEPTANCE OF THESE CONDITIONS.
*
* COPYRIGHT (C) 2001 SHARP MICROELECTRONICS OF THE AMERICAS, INC.
* CAMAS, WA
*
****************************************************************************/
#include <stdio.h>
#include "CS8900_enet_if_driver.h"
#include "CS8900_enet_eeprom_driver.h"
extern void enet_int_init(void);
extern void enet_int_clear(void);
extern void enet_if_wakeup(void);
extern void enet_if_mem_init(void);
extern void dummy_write(void);
extern UNS_16 * const enet_port_addr[];
extern UNS_32 dummy_write_en;
/*
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.
*/
enet_pp_t *enet_pp_data = (void *) 0x0;
// Local copy of the ethernet controller address
UNS_8 enetaddr [6];
// Number of RX and TX buffers. Each RX and TX buffer is allocated
// 1550 bytes in memory
#define NUM_BUFS 4
// Message queue structure
typedef struct
{
INT_32 messages_queued; // Number of packets queued (sb atomic)
INT_32 next_message_in; // Index into next packet in
INT_32 next_message_out; // Index into next packet out
buffer_t buffer [NUM_BUFS]; // Buffers
INT_32 psize [NUM_BUFS]; // Size of the packet
} queue_t;
// Message queues
queue_t tx, rx;
// Transmit on flag, used to indicate if the transmitter is available
// to transfer data
INT_32 enet_txon;
/*****************************************************************************
* Main functions - initialization
****************************************************************************/
/**********************************************************************
*
* Function: enet_init
*
* Purpose: Initialize the CS8900 Ethernet controller.
*
* Processing:
* The function configures the CS8900 Ethernet controller. The
* configuration is very basic. Interrupts are generated for
* TX and RX message frames only. All other interrupts are disabled.
* The SMA_priority driver is used to route the ethernet interrupt
* when it occurs. The SMA_priority driver should be initialized and
* interrupts enabled prior to using this initialization service.
*
* Parameters: None
*
* Outputs: None
*
* Returns: '0' if the initialization was successful,
* '1' if the chip ID was not found,
* '2' if the EEPROM was not valid.
*
* Notes:
* This driver requires that the external interrupt source be set to
* 'level high active' mode. Using the edge triggered mode may cause
* interrupts to be missed.
*
**********************************************************************/
INT_32 enet_init (void)
{
UNS_16 volatile temp;
// Initialize chip memory interface and disable sleep signal
enet_if_mem_init ();
enet_if_wakeup ();
// The CS8900 requires the nSBHE line to toggle once after reset.
dummy_write();
/*
* Verify that CS8900A controller exists, return an error status if it
* is not found. The CS8900A ISA registration number is 0x0E, 0x63 at
* PacketPage address 0x0. This will be read if the controller exists.
*/
enet_set_pp_addr (&enet_pp_data->bus_regs.chip_id_h, 1);
if (enet_read_data () != 0x630E)
{
return (1);
}
// DISABLED - EEPROM_OK bit not active, but address was loaded!
// Verify that the ethernet controller address was loaded from
// the EEPROM. (Actually, this service just verifies that any data
// in the EEPROM was loaded correctly).
enet_set_pp_addr (&enet_pp_data->stco_regs.reg16_selfst, 0);
if ((enet_read_data() & EEOK) == 0)
{
// EEPROM data was invalid or non-existant, no default MAC
// address was available for the ethernet controller
return (2);
}
//Need to init EEPROM structure with data from chip at this point!!
// Before starting with the configuration, disable the receiver
// and transmitter
enet_set_pp_addr (&enet_pp_data->stco_regs.reg13_linectl, 0);
enet_write_data (RLINECTL | AUTOAUI);
// Disable ethernet controller DMA
enet_set_dma_chan(DMA_NONE);
// Set memory base address to 0x0 (mode not used in this driver)
enet_set_pp_addr (&enet_pp_data->bus_regs.mem_base_h, 1);
enet_write_data (0x0); // High half of word
enet_write_data (0x0); // Low half of word
enet_8900e2_set_io(0x0);
// Set boot PROM address and size to 0x0 (not used)
enet_set_pp_addr (&enet_pp_data->bus_regs.boot_pr_addr_h, 1);
enet_write_data (0x0); // High half of boot PROM address
enet_write_data (0x0); // Low half of boot PROM address
enet_write_data (0x0); // High half of boot PROM mask (size)
enet_write_data (0x0); // 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
enet_set_pp_addr (&enet_pp_data->stco_regs.reg3_rxcfg, 0);
enet_write_data (RRXCFG | 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
enet_set_pp_addr (&enet_pp_data->stco_regs.reg5_rxctl, 0);
enet_write_data (RRXCTL | RXOKA | INDIVIDUALA);
// Configure the transmitter
// Interrupt generated on completion of TX interrupt
enet_set_pp_addr (&enet_pp_data->stco_regs.reg7_txcfg, 0);
enet_write_data (RTXCFG | TXOKIE);
// Configure the buffers
// Interrupt ONLY when ready to transfer a new packet
enet_set_pp_addr (&enet_pp_data->stco_regs.regb_bufcfg, 0);
#ifdef IRQACTIVE
enet_write_data (RBUFCFG | RDY4TXIE);
#else
// Setup for polling mode
enet_write_data (RBUFCFG);
#endif
// Configure self control
// No support for hardware power modes
// Status LEDS are active
enet_set_pp_addr (&enet_pp_data->stco_regs.reg15_selfctl, 0);
enet_write_data (RSELFCTL);
// Configure bus control
// Disable memory mode and IOCHRDY
// Enable interrupts
enet_set_pp_addr (&enet_pp_data->stco_regs.reg17_busctl, 0);
#ifdef IRQACTIVE
enet_write_data (RBUSCTL | ENABLERQ);
#else
enet_write_data (RBUSCTL);
#endif
// Configure test control
// No test modes are enabled
enet_set_pp_addr (&enet_pp_data->stco_regs.reg19_testctl, 0);
enet_write_data (RTESTCTL);
// Clear hash filter, not used
enet_set_pp_addr (&enet_pp_data->filter_regs.hash_filter, 1);
enet_write_data (0x0);
enet_write_data (0x0);
enet_write_data (0x0);
enet_write_data (0x0);
// Get local copy of ethernet controller address. This should
// of been loaded from the EEPROM at reset
enet_get_address (enetaddr);
// Setup interrupt line INTR0 as the active interrupt. The
// ethernet interrupt is active high and must be configued.
enet_set_irq_number(INTR0);
// Clear any pending interrupts and all messages from controller
temp = 1;
while (temp != 0)
{
// Read status queue until all interrupts have been cleared
temp = enet_read_port (isq);
}
enet_int_init();
// Initialize queue structures
tx.messages_queued = 0;
tx.next_message_in = 0;
tx.next_message_out = 0;
rx.messages_queued = 0;
rx.next_message_in = 0;
rx.next_message_out = 0;
// Transmitter initially idle
enet_txon = 0;
// The ethernet transceiver is not enabled as part of this function
return 0;
}
/**********************************************************************
*
* Function: enet_disable_transceiver
*
* Purpose: Disable the ethernet receiver and transmitter.
*
* Processing: The ethernet transceiver is disabled.
*
* Parameters: None
*
* Outputs: None
*
* Returns: Nothing
*
* Notes: None
*
*
**********************************************************************/
void enet_disable_transceiver (void)
{
// Disable receiver and transmitter
enet_set_pp_addr (&enet_pp_data->stco_regs.reg13_linectl, 0);
enet_write_data (RLINECTL | AUTOAUI);
}
/**********************************************************************
*
* Function: enet_enable_transceiver
*
* Purpose: Enable the ethernet receiver and transmitter.
*
* Processing: The ethernet transceiver is enabled.
*
* Parameters: None
*
* Outputs: None
*
* Returns: Nothing
*
* Notes: None
*
**********************************************************************/
void enet_enable_transceiver (void)
{
// Enable receiver and transmitter
enet_set_pp_addr (&enet_pp_data->stco_regs.reg13_linectl, 0);
enet_write_data (RLINECTL | AUTOAUI | SERRXON | SERTXON);
}
/*****************************************************************************
* Main functions - Interrupt handling
****************************************************************************/
/**********************************************************************
*
* Function: enet_rx_event
*
* Purpose: Ethernet receive event interrupt handler
*
* Processing:
* The receive event will occur when an ethernet packet is received
* with no errors and has passed the address filters. The packet is
* extracted from the ethernet controller into the rx message queues
* and awaits processing from background tasks.
*
* Parameters:
* status: Status word read from interrupt handler entry
*
* Outputs: None
*
* Returns: Nothing
*
* Notes: None
*
**********************************************************************/
void enet_rx_event (UNS_16 status)
{
INT_32 mlen;
// Is any buffer space available
if (rx.messages_queued < NUM_BUFS)
{
// Space exists for the message, check the status
if ((status & RXOK) == RXOK)
{
// Last message received was valid, process it
// Read the length of the message in bytes
enet_set_pp_addr (&enet_pp_data->frame_regs.rxlen, 1);
mlen = (INT_32) enet_read_data ();
// 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
mlen = (mlen + (mlen & 0x1)) / 2;
// Copy the packet from the controller to the buffer
enet_read_block ((UNS_16 *) &rx.buffer [rx.next_message_in],
mlen);
// Save length of message (in bytes)
rx.psize [rx.next_message_in] = mlen << 1;
// Setup next message queue pointer
rx.next_message_in++;
if (rx.next_message_in >= NUM_BUFS)
{
rx.next_message_in = 0;
}
// Increment number of queued RX messages
rx.messages_queued++;
}
}
}
/**********************************************************************
*
* Function: enet_tx_event
*
* Purpose: Ethernet transmit event interrupt handler
*
* Processing: Neesd
*
* Parameters:
* status: Status word read from interrupt handler entry
*
* Outputs: None
*
* Returns: Nothing
*
* Notes: None
*
**********************************************************************/
void enet_tx_event (UNS_16 status)
{
// Check to see if transfer completed ok
if ((status & TXOK) == TXOK)
{
// Transfer completed OK, do nothing
;
}
}
/**********************************************************************
*
* Function: enet_buf_event
*
* Purpose: Ethernet buffer event interrupt handler
*
* Processing:
*
* Parameters:
* status: Status word read from interrupt handler entry
*
* Outputs: None
*
* Returns: Nothing
*
* Notes:
*
**********************************************************************/
void enet_buf_event (UNS_16 status)
{
// Is controller ready to transmit data?
if ((status & RDY4TX) == RDY4TX)
{
// Transmitter is idle
enet_txon = 0;
}
// Are any more packets ready to send?
if (tx.messages_queued > 0)
{
// Another packet is waiting, transfer it if idle
if (enet_txon == 0)
{
// Send next message in queue
enet_send_packet ((char *) &tx.buffer [tx.next_message_out],
tx.psize [tx.next_message_out]);
// Lower queued message count
tx.messages_queued--;
// Remove sent message from queue
tx.next_message_out++;
if (tx.next_message_out > NUM_BUFS)
{
tx.next_message_out = 0;
}
// Transmitter is now on
enet_txon = 1;
}
}
}
/**********************************************************************
*
* Function: enet_isr
*
* Purpose: Ethernet Transmit/Receive interrupt.
*
* Processing:
* This functions services the ethernet controller when an interrupt
* is generated by the controller. Interrupts are broken into three
* different types: Receive (RX), Transmit (TX), and Other. Receive
* interrupts occur when an ethernet packet for the selected card (or
* broadcast) address is received. Transmit interrupts occur when a
* packet is ready to be sent. Other interrupts are not supported
* by this driver.
*
* Parameters: None
*
* Outputs: None
*
* Returns: Nothing
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -