| /*********************************************************************** |
| * |
| * 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->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("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); |
| } |