|  | /*********************************************************************** | 
|  | * | 
|  | * Copyright (c) 2004	Cucy Systems (http://www.cucy.com) | 
|  | * Curt Brune <curt@cucy.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 | 
|  | * | 
|  | * Description:   Ethernet interface for Samsung S3C4510B SoC | 
|  | */ | 
|  |  | 
|  | #include <common.h> | 
|  | #include <command.h> | 
|  | #include <net.h> | 
|  | #include <asm/hardware.h> | 
|  | #include "s3c4510b_eth.h" | 
|  |  | 
|  | static TX_FrameDescriptor    txFDbase[ETH_MaxTxFrames]; | 
|  | static MACFrame           txFrameBase[ETH_MaxTxFrames]; | 
|  | static RX_FrameDescriptor    rxFDbase[PKTBUFSRX]; | 
|  | static ETH                      m_eth; | 
|  |  | 
|  | static s32 TxFDinit( ETH *eth) { | 
|  |  | 
|  | s32 i; | 
|  | MACFrame *txFrmBase; | 
|  |  | 
|  | /* disable cache for access to the TX buffers */ | 
|  | txFrmBase = (MACFrame *)( (u32)txFrameBase | CACHE_DISABLE_MASK); | 
|  |  | 
|  | /* store start of Tx descriptors and set current */ | 
|  | eth->m_curTX_FD  =  (TX_FrameDescriptor *) ((u32)txFDbase | CACHE_DISABLE_MASK); | 
|  | eth->m_baseTX_FD = eth->m_curTX_FD; | 
|  |  | 
|  | for ( i = 0; i < ETH_MaxTxFrames; i++) { | 
|  | eth->m_baseTX_FD[i].m_frameDataPtr.bf.dataPtr = (u32)&txFrmBase[i]; | 
|  | eth->m_baseTX_FD[i].m_frameDataPtr.bf.owner   = 0x0; /* CPU owner */ | 
|  | eth->m_baseTX_FD[i].m_opt.ui                  = 0x0; | 
|  | eth->m_baseTX_FD[i].m_status.ui               = 0x0; | 
|  | eth->m_baseTX_FD[i].m_nextFD                  = ð->m_baseTX_FD[i+1]; | 
|  | } | 
|  |  | 
|  | /* make the list circular */ | 
|  | eth->m_baseTX_FD[i-1].m_nextFD          = ð->m_baseTX_FD[0]; | 
|  |  | 
|  | PUT_REG( REG_BDMATXPTR, (u32)eth->m_curTX_FD); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static s32 RxFDinit( ETH *eth) { | 
|  |  | 
|  | s32 i; | 
|  | /*  MACFrame *rxFrmBase; */ | 
|  |  | 
|  | /* disable cache for access to the RX buffers */ | 
|  | /*  rxFrmBase = (MACFrame *)( (u32)rxFrameBase | CACHE_DISABLE_MASK); */ | 
|  |  | 
|  | /* store start of Rx descriptors and set current */ | 
|  | eth->m_curRX_FD = (RX_FrameDescriptor *)((u32)rxFDbase | CACHE_DISABLE_MASK); | 
|  | eth->m_baseRX_FD = eth->m_curRX_FD; | 
|  | for ( i = 0; i < PKTBUFSRX; i++) { | 
|  | eth->m_baseRX_FD[i].m_frameDataPtr.bf.dataPtr = (u32)NetRxPackets[i] | CACHE_DISABLE_MASK; | 
|  | eth->m_baseRX_FD[i].m_frameDataPtr.bf.owner   = 0x1; /* BDMA owner */ | 
|  | eth->m_baseRX_FD[i].m_reserved                = 0x0; | 
|  | eth->m_baseRX_FD[i].m_status.ui               = 0x0; | 
|  | eth->m_baseRX_FD[i].m_nextFD                  = ð->m_baseRX_FD[i+1]; | 
|  | } | 
|  |  | 
|  | /* make the list circular */ | 
|  | eth->m_baseRX_FD[i-1].m_nextFD                  = ð->m_baseRX_FD[0]; | 
|  |  | 
|  | PUT_REG( REG_BDMARXPTR, (u32)eth->m_curRX_FD); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Public u-boot interface functions below | 
|  | */ | 
|  |  | 
|  | int eth_init(bd_t *bis) | 
|  | { | 
|  |  | 
|  | ETH *eth = &m_eth; | 
|  |  | 
|  | /* store our MAC address */ | 
|  | eth_getenv_enetaddr("ethaddr", eth->m_mac); | 
|  |  | 
|  | /* setup DBMA and MAC */ | 
|  | PUT_REG( REG_BDMARXCON, ETH_BRxRS);   /* reset BDMA RX machine */ | 
|  | PUT_REG( REG_BDMATXCON, ETH_BTxRS);   /* reset BDMA TX machine */ | 
|  | PUT_REG( REG_MACCON   , ETH_SwReset); /* reset MAC machine */ | 
|  | PUT_REG( REG_BDMARXLSZ, sizeof(MACFrame)); | 
|  | PUT_REG( REG_MACCON   , 0);           /* reset MAC machine */ | 
|  |  | 
|  | /* init frame descriptors */ | 
|  | TxFDinit( eth); | 
|  | RxFDinit( eth); | 
|  |  | 
|  | /* init the CAM with our MAC address */ | 
|  | PUT_REG( REG_CAM_BASE,       (eth->m_mac[0] << 24) | | 
|  | (eth->m_mac[1] << 16) | | 
|  | (eth->m_mac[2] <<  8) | | 
|  | (eth->m_mac[3])); | 
|  | PUT_REG( REG_CAM_BASE + 0x4, (eth->m_mac[4] << 24) | | 
|  | (eth->m_mac[5] << 16)); | 
|  |  | 
|  | /* enable CAM address 1 -- the MAC we just loaded */ | 
|  | PUT_REG( REG_CAMEN, 0x1); | 
|  |  | 
|  | PUT_REG( REG_CAMCON, | 
|  | ETH_BroadAcc |	/* accept broadcast packetes */ | 
|  | ETH_CompEn); /* enable compare mode (check against the CAM) */ | 
|  |  | 
|  | /* configure the BDMA Transmitter control */ | 
|  | PUT_REG( REG_BDMATXCON, | 
|  | ETH_BTxBRST   |	/* BDMA Tx burst size 16 words  */ | 
|  | ETH_BTxMSL110 |	/* BDMA Tx wait to fill 6/8 of the BDMA */ | 
|  | ETH_BTxSTSKO  |	/* BDMA Tx interrupt(Stop) on non-owner TX FD */ | 
|  | ETH_BTxEn);	/* BDMA Tx Enable  */ | 
|  |  | 
|  | /* configure the MAC Transmitter control */ | 
|  | PUT_REG( REG_MACTXCON, | 
|  | ETH_EnComp | /* interrupt when the MAC transmits or discards packet */ | 
|  | ETH_TxEn);	/* MAC transmit enable */ | 
|  |  | 
|  | /* configure the BDMA Receiver control */ | 
|  | PUT_REG( REG_BDMARXCON, | 
|  | ETH_BRxBRST   |	/* BDMA Rx Burst Size 16 words */ | 
|  | ETH_BRxSTSKO  |	/* BDMA Rx interrupt(Stop) on non-owner RX FD */ | 
|  | ETH_BRxMAINC  |	/* BDMA Rx Memory Address increment */ | 
|  | ETH_BRxDIE    |	/* BDMA Rx Every Received Frame Interrupt Enable */ | 
|  | ETH_BRxNLIE   |	/* BDMA Rx NULL List Interrupt Enable */ | 
|  | ETH_BRxNOIE   |	/* BDMA Rx Not Owner Interrupt Enable */ | 
|  | ETH_BRxLittle |	/* BDMA Rx Little endian */ | 
|  | ETH_BRxEn);	/* BDMA Rx Enable */ | 
|  |  | 
|  | /* configure the MAC Receiver control */ | 
|  | PUT_REG( REG_MACRXCON, | 
|  | ETH_RxEn);	/* MAC ETH_RxEn */ | 
|  |  | 
|  | return 0; | 
|  |  | 
|  | } | 
|  |  | 
|  | /* Send a packet	*/ | 
|  | s32 eth_send(volatile void *packet, s32 length) | 
|  | { | 
|  |  | 
|  | u32 i; | 
|  | ETH *eth = &m_eth; | 
|  |  | 
|  | if ( eth->m_curTX_FD->m_frameDataPtr.bf.owner) { | 
|  | printf("eth_send(): TX Frame.  CPU not owner.\n"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* copy user data into frame data pointer */ | 
|  | memcpy((void *)((u32)(eth->m_curTX_FD->m_frameDataPtr.bf.dataPtr)), | 
|  | (void *)packet, | 
|  | length); | 
|  |  | 
|  | /* Set TX Frame flags */ | 
|  | eth->m_curTX_FD->m_opt.bf.widgetAlign  = 0; | 
|  | eth->m_curTX_FD->m_opt.bf.frameDataDir = 1; | 
|  | eth->m_curTX_FD->m_opt.bf.littleEndian = 1; | 
|  | eth->m_curTX_FD->m_opt.bf.macTxIrqEnbl = 1; | 
|  | eth->m_curTX_FD->m_opt.bf.no_crc       = 0; | 
|  | eth->m_curTX_FD->m_opt.bf.no_padding   = 0; | 
|  |  | 
|  | /* Set TX Frame length */ | 
|  | eth->m_curTX_FD->m_status.bf.len       = length; | 
|  |  | 
|  | /* Change ownership to BDMA */ | 
|  | eth->m_curTX_FD->m_frameDataPtr.bf.owner = 1; | 
|  |  | 
|  | /* Enable MAC and BDMA Tx control register */ | 
|  | SET_REG( REG_BDMATXCON, ETH_BTxEn); | 
|  | SET_REG( REG_MACTXCON,  ETH_TxEn); | 
|  |  | 
|  | /* poll on TX completion status */ | 
|  | while ( !eth->m_curTX_FD->m_status.bf.complete) { | 
|  | /* sleep  */ | 
|  | for ( i = 0; i < 0x10000; i ++); | 
|  | } | 
|  |  | 
|  | /* Change the Tx frame descriptor for next use */ | 
|  | eth->m_curTX_FD = eth->m_curTX_FD->m_nextFD; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Check for received packets	*/ | 
|  | s32 eth_rx (void) | 
|  | { | 
|  | s32 nLen = 0; | 
|  | ETH *eth = &m_eth; | 
|  |  | 
|  | /* check if packet ready */ | 
|  | if ( (GET_REG( REG_BDMASTAT)) & ETH_S_BRxRDF) { | 
|  | /* process all waiting packets */ | 
|  | while ( !eth->m_curRX_FD->m_frameDataPtr.bf.owner) { | 
|  | nLen = eth->m_curRX_FD->m_status.bf.len; | 
|  | /* call back u-boot -- may call eth_send() */ | 
|  | NetReceive ((u8 *)eth->m_curRX_FD->m_frameDataPtr.ui, nLen); | 
|  | /* set owner back to CPU */ | 
|  | eth->m_curRX_FD->m_frameDataPtr.bf.owner = 1; | 
|  | /* clear status */ | 
|  | eth->m_curRX_FD->m_status.ui = 0x0; | 
|  | /* advance to next descriptor */ | 
|  | eth->m_curRX_FD = eth->m_curRX_FD->m_nextFD; | 
|  | /* clear received frame bit */ | 
|  | PUT_REG( REG_BDMASTAT, ETH_S_BRxRDF); | 
|  | } | 
|  | } | 
|  |  | 
|  | return nLen; | 
|  | } | 
|  |  | 
|  | /* Halt ethernet engine */ | 
|  | void eth_halt(void) | 
|  | { | 
|  | /* disable MAC */ | 
|  | PUT_REG( REG_MACCON, ETH_HaltReg); | 
|  | } |