diff options
Diffstat (limited to 'drivers/s3c4510b_eth.c')
-rw-r--r-- | drivers/s3c4510b_eth.c | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/drivers/s3c4510b_eth.c b/drivers/s3c4510b_eth.c new file mode 100644 index 0000000..694703c --- /dev/null +++ b/drivers/s3c4510b_eth.c @@ -0,0 +1,246 @@ +/*********************************************************************** + * + * 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> + +#ifdef CONFIG_DRIVER_S3C4510_ETH + +#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->m_mac = bis->bi_enetaddr; + + /* 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(__FUNCTION__"(): TX Frame. CPU not owner.\n"); + return -1; + } + + /* copy user data into frame data pointer */ + memcpy((void *)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); +} + +#endif |