/*----------------------------------------------------------------------------<br /> * R T L - T C P N E T<br /> *----------------------------------------------------------------------------<br /> * Name: LPC23_EMAC.C<br /> * Purpose: Driver for Philips LPC2378 EMAC Ethernet Controller<br /> * Rev.: V3.20<br /> *----------------------------------------------------------------------------<br /> * This code is part of the RealView Run-Time Library.<br /> * Copyright (c) 2004-2008 KEIL - An ARM Company. All rights reserved.<br /> *---------------------------------------------------------------------------*/<br /><br />#include <Net_Config.h><br />#include "LPC23_EMAC.h"<br />#include <LPC23xx.H> /* LPC23xx definitions */<br /><br />/* The following macro definitions may be used to select the speed<br /> of the physical link:<br /><br /> _10MBIT_ - connect at 10 MBit only<br /> _100MBIT_ - connect at 100 MBit only<br /><br /> By default an autonegotiation of the link speed is used. This may take<br /> longer to connect, but it works for 10MBit and 100MBit physical links. */<br /><br />/* Net_Config.c */<br />extern U8 own_hw_adr[];<br /><br />/* Local variables */<br /><br />/* EMAC local DMA Descriptors. */<br />static RX_Desc Rx_Desc[NUM_RX_FRAG];<br />static __align(8) RX_Stat Rx_Stat[NUM_RX_FRAG]; /* Must be 8-Byte alligned */<br />static TX_Desc Tx_Desc[NUM_TX_FRAG];<br />static TX_Stat Tx_Stat[NUM_TX_FRAG];<br /><br />/* EMAC local DMA buffers. */<br />static U32 rx_buf[NUM_RX_FRAG][ETH_FRAG_SIZE>>2];<br />static U32 tx_buf[NUM_TX_FRAG][ETH_FRAG_SIZE>>2];<br /><br />/*----------------------------------------------------------------------------<br /> * EMAC Ethernet Driver Functions<br /> *----------------------------------------------------------------------------<br /> * Required functions for Ethernet driver module:<br /> * a. Polling mode: - void init_ethernet ()<br /> * - void send_frame (OS_FRAME *frame)<br /> * - void poll_ethernet (void)<br /> * b. Interrupt mode: - void init_ethernet ()<br /> * - void send_frame (OS_FRAME *frame)<br /> * - void int_enable_eth ()<br /> * - void int_disable_eth ()<br /> * - interrupt function<br /> *---------------------------------------------------------------------------*/<br /><br />/* Local Function Prototypes */<br />static void interrupt_ethernet (void) __irq;<br />static void rx_descr_init (void);<br />static void tx_descr_init (void);<br />static void write_PHY (U32 PhyReg, U16 Value);<br />static U16 read_PHY (U32 PhyReg);<br /><br />/*--------------------------- init_ethernet ---------------------------------*/<br /><br />void init_ethernet (void) {<br /> /* Initialize the EMAC ethernet controller. */<br /> U32 regv,tout,id1,id2;<br /><br /> /* Power Up the EMAC controller. */<br /> PCONP |= 0x40000000;<br /><br /> /* Enable P1 Ethernet Pins. */<br /> if (MAC_MODULEID == OLD_EMAC_MODULE_ID) {<br /> /* For the first silicon rev.'-' ID P1.6 should be set. */<br /> PINSEL2 = 0x50151105;<br /> }<br /> else {<br /> /* on rev. 'A' and later, P1.6 should NOT be set. */<br /> PINSEL2 = 0x50150105;<br /> }<br /> PINSEL3 = (PINSEL3 & ~0x0000000F) | 0x00000005;<br /><br /> /* Reset all EMAC internal modules. */<br /> MAC_MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX |<br /> MAC1_SIM_RES | MAC1_SOFT_RES;<br /> MAC_COMMAND = CR_REG_RES | CR_TX_RES | CR_RX_RES;<br /><br /> /* A short delay after reset. */<br /> for (tout = 100; tout; tout--);<br /><br /> /* Initialize MAC control registers. */<br /> MAC_MAC1 = MAC1_PASS_ALL;<br /> MAC_MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;<br /> MAC_MAXF = ETH_MAX_FLEN;<br /> MAC_CLRT = CLRT_DEF;<br /> MAC_IPGR = IPGR_DEF;<br /><br /> /* Enable Reduced MII interface. */<br /> MAC_COMMAND = CR_RMII | CR_PASS_RUNT_FRM;<br /><br /> /* Reset Reduced MII Logic. */<br /> MAC_SUPP = SUPP_RES_RMII;<br /> for (tout = 100; tout; tout--);<br /> MAC_SUPP = 0;<br /><br /> /* Put the DP83848C in reset mode */<br /> write_PHY (PHY_REG_BMCR, 0x8000);<br /><br /> /* Wait for hardware reset to end. */<br /> for (tout = 0; tout < 0x100000; tout++) {<br /> regv = read_PHY (PHY_REG_BMCR);<br /> if (!(regv & 0x8800)) {<br /> /* Reset complete, device not Power Down. */<br /> break;<br /> }<br /> }<br /><br /> /* Check if this is a DP83848C PHY. */<br /> id1 = read_PHY (PHY_REG_IDR1);<br /> id2 = read_PHY (PHY_REG_IDR2);<br /><br /> if (((id1 << 16) | (id2 & 0xFFF0)) == DP83848C_ID) {<br /> /* Configure the PHY device */<br />#if defined (_10MBIT_)<br /> /* Connect at 10MBit */<br /> write_PHY (PHY_REG_BMCR, PHY_FULLD_10M);<br />#elif defined (_100MBIT_)<br /> /* Connect at 100MBit */<br /> write_PHY (PHY_REG_BMCR, PHY_FULLD_100M);<br />#else<br /> /* Use autonegotiation about the link speed. */<br /> write_PHY (PHY_REG_BMCR, PHY_AUTO_NEG);<br /> /* Wait to complete Auto_Negotiation. */<br /> for (tout = 0; tout < 0x100000; tout++) {<br /> regv = read_PHY (PHY_REG_BMSR);<br /> if (regv & 0x0020) {<br /> /* Autonegotiation Complete. */<br /> break;<br /> }<br /> }<br />#endif<br /> }<br /><br /> /* Check the link status. */<br /> for (tout = 0; tout < 0x10000; tout++) {<br /> regv = read_PHY (PHY_REG_STS);<br /> if (regv & 0x0001) {<br /> /* Link is on. */<br /> break;<br /> }<br /> }<br /><br /> /* Configure Full/Half Duplex mode. */<br /> if (regv & 0x0004) {<br /> /* Full duplex is enabled. */<br /> MAC_MAC2 |= MAC2_FULL_DUP;<br /> MAC_COMMAND |= CR_FULL_DUP;<br /> MAC_IPGT = IPGT_FULL_DUP;<br /> }<br /> else {<br /> /* Half duplex mode. */<br /> MAC_IPGT = IPGT_HALF_DUP;<br /> }<br /><br /> /* Configure 100MBit/10MBit mode. */<br /> if (regv & 0x0002) {<br /> /* 10MBit mode. */<br /> MAC_SUPP = 0;<br /> }<br /> else {<br /> /* 100MBit mode. */<br /> MAC_SUPP = SUPP_SPEED;<br /> }<br /><br /> /* Set the Ethernet MAC Address registers */<br /> MAC_SA0 = ((U32)own_hw_adr[5] << 8) | (U32)own_hw_adr[4];<br /> MAC_SA1 = ((U32)own_hw_adr[3] << 8) | (U32)own_hw_adr[2];<br /> MAC_SA2 = ((U32)own_hw_adr[1] << 8) | (U32)own_hw_adr[0];<br /><br /> /* Initialize Tx and Rx DMA Descriptors */<br /> rx_descr_init ();<br /> tx_descr_init ();<br /><br /> /* Receive Broadcast, Multicast and Perfect Match Packets */<br /> MAC_RXFILTERCTRL = RFC_MCAST_EN | RFC_BCAST_EN | RFC_PERFECT_EN;<br /><br /> /* Enable EMAC interrupts. */<br /> MAC_INTENABLE = INT_RX_DONE | INT_TX_DONE;<br /><br /> /* Reset all interrupts */<br /> MAC_INTCLEAR = 0xFFFF;<br /><br /> /* Enable receive and transmit mode of MAC Ethernet core */<br /> MAC_COMMAND |= (CR_RX_EN | CR_TX_EN);<br /> MAC_MAC1 |= MAC1_REC_EN;<br /><br /> /* Configure VIC for EMAC interrupt. */<br /> VICVectAddr21 = (U32)interrupt_ethernet;<br />}<br /><br /><br />/*--------------------------- int_enable_eth --------------------------------*/<br /><br />void int_enable_eth (void) {<br /> /* Ethernet Interrupt Enable function. */<br /> VICIntEnable |= 1 << 21;<br />}<br /><br /><br />/*--------------------------- int_disable_eth -------------------------------*/<br /><br />void int_disable_eth (void) {<br /> /* Ethernet Interrupt Disable function. */<br /> VICIntEnClr = 1 << 21;<br />}<br /><br /><br />/*--------------------------- send_frame ------------------------------------*/<br /><br />void send_frame (OS_FRAME *frame) {<br /> /* Send frame to EMAC ethernet controller */<br /> U32 idx,len;<br /> U32 *sp,*dp;<br /><br /> idx = MAC_TXPRODUCEINDEX;<br /> sp = (U32 *)&frame->data[0];<br /> dp = (U32 *)Tx_Desc[idx].Packet;<br /><br /> /* Copy frame data to EMAC packet buffers. */<br /> for (len = (frame->length + 3) >> 2; len; len--) {<br /> *dp++ = *sp++;<br /> }<br /> Tx_Desc[idx].Ctrl = (frame->length-1) | (TCTRL_INT | TCTRL_LAST);<br /><br /> /* Start frame transmission. */<br /> if (++idx == NUM_TX_FRAG) idx = 0;<br /> MAC_TXPRODUCEINDEX = idx;<br />}<br /><br /><br />/*--------------------------- interrupt_ethernet ----------------------------*/<br /><br />static void interrupt_ethernet (void) __irq {<br /> /* EMAC Ethernet Controller Interrupt function. */<br /> OS_FRAME *frame;<br /> U32 idx,int_stat,RxLen,info;<br /> U32 *sp,*dp;<br /><br /> while ((int_stat = (MAC_INTSTATUS & MAC_INTENABLE)) != 0) {<br /> MAC_INTCLEAR = int_stat;<br /> if (int_stat & INT_RX_DONE) {<br /> /* Packet received, check if packet is valid. */<br /> idx = MAC_RXCONSUMEINDEX;<br /> while (idx != MAC_RXPRODUCEINDEX) {<br /> info = Rx_Stat[idx].Info;<br /> if (!(info & RINFO_LAST_FLAG)) {<br /> goto rel;<br /> }<br /><br /> RxLen = (info & RINFO_SIZE) - 3;<br /> if (RxLen > ETH_MTU || (info & RINFO_ERR_MASK)) {<br /> /* Invalid frame, ignore it and free buffer. */<br /> goto rel;<br /> }<br /> /* Flag 0x80000000 to skip sys_error() call when out of memory. */<br /> frame = alloc_mem (RxLen | 0x80000000);<br /> /* if 'alloc_mem()' has failed, ignore this packet. */<br /> if (frame != NULL) {<br /> dp = (U32 *)&frame->data[0];<br /> sp = (U32 *)Rx_Desc[idx].Packet;<br /> for (RxLen = (RxLen + 3) >> 2; RxLen; RxLen--) {<br /> *dp++ = *sp++;<br /> }<br /> put_in_queue (frame);<br /> }<br />rel: if (++idx == NUM_RX_FRAG) idx = 0;<br /> /* Release frame from EMAC buffer. */<br /> MAC_RXCONSUMEINDEX = idx;<br /> }<br /> }<br /> if (int_stat & INT_TX_DONE) {<br /> /* Frame transmit completed. */<br /> }<br /> }<br /> /* Acknowledge the interrupt. */<br /> VICVectAddr = 0;<br />}<br /><br /><br />/*--------------------------- rx_descr_init ---------------------------------*/<br /><br />static void rx_descr_init (void) {<br /> /* Initialize Receive Descriptor and Status array. */<br /> U32 i;<br /><br /> for (i = 0; i < NUM_RX_FRAG; i++) {<br /> Rx_Desc.Packet = (U32)&rx_buf;<br /> Rx_Desc.Ctrl = RCTRL_INT | (ETH_FRAG_SIZE-1);<br /> Rx_Stat.Info = 0;<br /> Rx_Stat.HashCRC = 0;<br /> }<br /><br /> /* Set EMAC Receive Descriptor Registers. */<br /> MAC_RXDESCRIPTOR = (U32)&Rx_Desc[0];<br /> MAC_RXSTATUS = (U32)&Rx_Stat[0];<br /> MAC_RXDESCRIPTORNUM = NUM_RX_FRAG-1;<br /><br /> /* Rx Descriptors Point to 0 */<br /> MAC_RXCONSUMEINDEX = 0;<br />}<br /><br /><br />/*--------------------------- tx_descr_init ---- ----------------------------*/<br /><br />static void tx_descr_init (void) {<br /> /* Initialize Transmit Descriptor and Status array. */<br /> U32 i;<br /><br /> for (i = 0; i < NUM_TX_FRAG; i++) {<br /> Tx_Desc.Packet = (U32)&tx_buf;<br /> Tx_Desc.Ctrl = 0;<br /> Tx_Stat.Info = 0;<br /> }<br /><br /> /* Set EMAC Transmit Descriptor Registers. */<br /> MAC_TXDESCRIPTOR = (U32)&Tx_Desc[0];<br /> MAC_TXSTATUS = (U32)&Tx_Stat[0];<br /> MAC_TXDESCRIPTORNUM = NUM_TX_FRAG-1;<br /><br /> /* Tx Descriptors Point to 0 */<br /> MAC_TXPRODUCEINDEX = 0;<br />}<br /><br /><br />/*--------------------------- write_PHY -------------------------------------*/<br /><br />static void write_PHY (U32 PhyReg, U16 Value) {<br /> /* Write a data 'Value' to PHY register 'PhyReg'. */<br /> U32 tout;<br /><br /> MAC_MADR = DP83848C_DEF_ADR | PhyReg;<br /> MAC_MWTD = Value;<br /><br /> /* Wait utill operation completed */<br /> tout = 0;<br /> for (tout = 0; tout < MII_WR_TOUT; tout++) {<br /> if ((MAC_MIND & MIND_BUSY) == 0) {<br /> break;<br /> }<br /> }<br />}<br /><br /><br />/*--------------------------- read_PHY --------------------------------------*/<br /><br />static U16 read_PHY (U32 PhyReg) {<br /> /* Read a PHY register 'PhyReg'. */<br /> U32 tout;<br /><br /> MAC_MADR = DP83848C_DEF_ADR | PhyReg;<br /> MAC_MCMD = MCMD_READ;<br /><br /> /* Wait until operation completed */<br /> tout = 0;<br /> for (tout = 0; tout < MII_RD_TOUT; tout++) {<br /> if ((MAC_MIND & MIND_BUSY) == 0) {<br /> break;<br /> }<br /> }<br /> MAC_MCMD = 0;<br /> return (MAC_MRDD);<br />}<br /><br />/*----------------------------------------------------------------------------<br /> * end of file<br /> *---------------------------------------------------------------------------*/<br /><br /><br /> |
|