wdenk | f2140d5 | 2004-07-01 16:30:44 +0000 | [diff] [blame] | 1 | /*********************************************************************** |
| 2 | * |
| 3 | * Copyright (c) 2004 Cucy Systems (http://www.cucy.com) |
| 4 | * Curt Brune <curt@cucy.com> |
| 5 | * |
| 6 | * See file CREDITS for list of people who contributed to this |
| 7 | * project. |
| 8 | * |
| 9 | * This program is free software; you can redistribute it and/or |
| 10 | * modify it under the terms of the GNU General Public License as |
| 11 | * published by the Free Software Foundation; either version 2 of |
| 12 | * the License, or (at your option) any later version. |
| 13 | * |
| 14 | * This program is distributed in the hope that it will be useful, |
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 17 | * GNU General Public License for more details. |
| 18 | * |
| 19 | * You should have received a copy of the GNU General Public License |
| 20 | * along with this program; if not, write to the Free Software |
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| 22 | * MA 02111-1307 USA |
| 23 | * |
| 24 | * Description: Ethernet interface for Samsung S3C4510B SoC |
| 25 | */ |
| 26 | |
| 27 | #include <common.h> |
wdenk | f2140d5 | 2004-07-01 16:30:44 +0000 | [diff] [blame] | 28 | #include <command.h> |
| 29 | #include <net.h> |
| 30 | #include <asm/hardware.h> |
| 31 | #include "s3c4510b_eth.h" |
| 32 | |
| 33 | static TX_FrameDescriptor txFDbase[ETH_MaxTxFrames]; |
| 34 | static MACFrame txFrameBase[ETH_MaxTxFrames]; |
| 35 | static RX_FrameDescriptor rxFDbase[PKTBUFSRX]; |
| 36 | static ETH m_eth; |
| 37 | |
| 38 | static s32 TxFDinit( ETH *eth) { |
| 39 | |
| 40 | s32 i; |
| 41 | MACFrame *txFrmBase; |
| 42 | |
| 43 | /* disable cache for access to the TX buffers */ |
| 44 | txFrmBase = (MACFrame *)( (u32)txFrameBase | CACHE_DISABLE_MASK); |
| 45 | |
| 46 | /* store start of Tx descriptors and set current */ |
| 47 | eth->m_curTX_FD = (TX_FrameDescriptor *) ((u32)txFDbase | CACHE_DISABLE_MASK); |
| 48 | eth->m_baseTX_FD = eth->m_curTX_FD; |
| 49 | |
| 50 | for ( i = 0; i < ETH_MaxTxFrames; i++) { |
| 51 | eth->m_baseTX_FD[i].m_frameDataPtr.bf.dataPtr = (u32)&txFrmBase[i]; |
| 52 | eth->m_baseTX_FD[i].m_frameDataPtr.bf.owner = 0x0; /* CPU owner */ |
| 53 | eth->m_baseTX_FD[i].m_opt.ui = 0x0; |
| 54 | eth->m_baseTX_FD[i].m_status.ui = 0x0; |
| 55 | eth->m_baseTX_FD[i].m_nextFD = ð->m_baseTX_FD[i+1]; |
| 56 | } |
| 57 | |
| 58 | /* make the list circular */ |
| 59 | eth->m_baseTX_FD[i-1].m_nextFD = ð->m_baseTX_FD[0]; |
| 60 | |
| 61 | PUT_REG( REG_BDMATXPTR, (u32)eth->m_curTX_FD); |
| 62 | |
| 63 | return 0; |
| 64 | } |
| 65 | |
| 66 | static s32 RxFDinit( ETH *eth) { |
| 67 | |
| 68 | s32 i; |
| 69 | /* MACFrame *rxFrmBase; */ |
| 70 | |
| 71 | /* disable cache for access to the RX buffers */ |
| 72 | /* rxFrmBase = (MACFrame *)( (u32)rxFrameBase | CACHE_DISABLE_MASK); */ |
| 73 | |
| 74 | /* store start of Rx descriptors and set current */ |
| 75 | eth->m_curRX_FD = (RX_FrameDescriptor *)((u32)rxFDbase | CACHE_DISABLE_MASK); |
| 76 | eth->m_baseRX_FD = eth->m_curRX_FD; |
| 77 | for ( i = 0; i < PKTBUFSRX; i++) { |
| 78 | eth->m_baseRX_FD[i].m_frameDataPtr.bf.dataPtr = (u32)NetRxPackets[i] | CACHE_DISABLE_MASK; |
| 79 | eth->m_baseRX_FD[i].m_frameDataPtr.bf.owner = 0x1; /* BDMA owner */ |
| 80 | eth->m_baseRX_FD[i].m_reserved = 0x0; |
| 81 | eth->m_baseRX_FD[i].m_status.ui = 0x0; |
| 82 | eth->m_baseRX_FD[i].m_nextFD = ð->m_baseRX_FD[i+1]; |
| 83 | } |
| 84 | |
| 85 | /* make the list circular */ |
| 86 | eth->m_baseRX_FD[i-1].m_nextFD = ð->m_baseRX_FD[0]; |
| 87 | |
| 88 | PUT_REG( REG_BDMARXPTR, (u32)eth->m_curRX_FD); |
| 89 | |
| 90 | return 0; |
| 91 | } |
| 92 | |
| 93 | /* |
| 94 | * Public u-boot interface functions below |
| 95 | */ |
| 96 | |
| 97 | int eth_init(bd_t *bis) |
| 98 | { |
| 99 | |
| 100 | ETH *eth = &m_eth; |
| 101 | |
| 102 | /* store our MAC address */ |
Mike Frysinger | b203965 | 2009-02-11 19:01:26 -0500 | [diff] [blame] | 103 | eth_getenv_enetaddr("ethaddr", eth->m_mac); |
wdenk | f2140d5 | 2004-07-01 16:30:44 +0000 | [diff] [blame] | 104 | |
| 105 | /* setup DBMA and MAC */ |
| 106 | PUT_REG( REG_BDMARXCON, ETH_BRxRS); /* reset BDMA RX machine */ |
| 107 | PUT_REG( REG_BDMATXCON, ETH_BTxRS); /* reset BDMA TX machine */ |
| 108 | PUT_REG( REG_MACCON , ETH_SwReset); /* reset MAC machine */ |
| 109 | PUT_REG( REG_BDMARXLSZ, sizeof(MACFrame)); |
| 110 | PUT_REG( REG_MACCON , 0); /* reset MAC machine */ |
| 111 | |
| 112 | /* init frame descriptors */ |
| 113 | TxFDinit( eth); |
| 114 | RxFDinit( eth); |
| 115 | |
| 116 | /* init the CAM with our MAC address */ |
| 117 | PUT_REG( REG_CAM_BASE, (eth->m_mac[0] << 24) | |
| 118 | (eth->m_mac[1] << 16) | |
| 119 | (eth->m_mac[2] << 8) | |
| 120 | (eth->m_mac[3])); |
| 121 | PUT_REG( REG_CAM_BASE + 0x4, (eth->m_mac[4] << 24) | |
| 122 | (eth->m_mac[5] << 16)); |
| 123 | |
| 124 | /* enable CAM address 1 -- the MAC we just loaded */ |
| 125 | PUT_REG( REG_CAMEN, 0x1); |
| 126 | |
| 127 | PUT_REG( REG_CAMCON, |
| 128 | ETH_BroadAcc | /* accept broadcast packetes */ |
| 129 | ETH_CompEn); /* enable compare mode (check against the CAM) */ |
| 130 | |
| 131 | /* configure the BDMA Transmitter control */ |
| 132 | PUT_REG( REG_BDMATXCON, |
| 133 | ETH_BTxBRST | /* BDMA Tx burst size 16 words */ |
| 134 | ETH_BTxMSL110 | /* BDMA Tx wait to fill 6/8 of the BDMA */ |
| 135 | ETH_BTxSTSKO | /* BDMA Tx interrupt(Stop) on non-owner TX FD */ |
| 136 | ETH_BTxEn); /* BDMA Tx Enable */ |
| 137 | |
| 138 | /* configure the MAC Transmitter control */ |
| 139 | PUT_REG( REG_MACTXCON, |
| 140 | ETH_EnComp | /* interrupt when the MAC transmits or discards packet */ |
| 141 | ETH_TxEn); /* MAC transmit enable */ |
| 142 | |
| 143 | /* configure the BDMA Receiver control */ |
| 144 | PUT_REG( REG_BDMARXCON, |
| 145 | ETH_BRxBRST | /* BDMA Rx Burst Size 16 words */ |
| 146 | ETH_BRxSTSKO | /* BDMA Rx interrupt(Stop) on non-owner RX FD */ |
| 147 | ETH_BRxMAINC | /* BDMA Rx Memory Address increment */ |
| 148 | ETH_BRxDIE | /* BDMA Rx Every Received Frame Interrupt Enable */ |
| 149 | ETH_BRxNLIE | /* BDMA Rx NULL List Interrupt Enable */ |
| 150 | ETH_BRxNOIE | /* BDMA Rx Not Owner Interrupt Enable */ |
| 151 | ETH_BRxLittle | /* BDMA Rx Little endian */ |
| 152 | ETH_BRxEn); /* BDMA Rx Enable */ |
| 153 | |
| 154 | /* configure the MAC Receiver control */ |
| 155 | PUT_REG( REG_MACRXCON, |
| 156 | ETH_RxEn); /* MAC ETH_RxEn */ |
| 157 | |
| 158 | return 0; |
| 159 | |
| 160 | } |
| 161 | |
| 162 | /* Send a packet */ |
| 163 | s32 eth_send(volatile void *packet, s32 length) |
| 164 | { |
| 165 | |
| 166 | u32 i; |
| 167 | ETH *eth = &m_eth; |
| 168 | |
| 169 | if ( eth->m_curTX_FD->m_frameDataPtr.bf.owner) { |
wdenk | ce4832c | 2004-10-17 21:12:06 +0000 | [diff] [blame] | 170 | printf("eth_send(): TX Frame. CPU not owner.\n"); |
wdenk | f2140d5 | 2004-07-01 16:30:44 +0000 | [diff] [blame] | 171 | return -1; |
| 172 | } |
| 173 | |
| 174 | /* copy user data into frame data pointer */ |
Wolfgang Denk | a923f11 | 2007-11-18 17:11:09 +0100 | [diff] [blame] | 175 | memcpy((void *)((u32)(eth->m_curTX_FD->m_frameDataPtr.bf.dataPtr)), |
wdenk | f2140d5 | 2004-07-01 16:30:44 +0000 | [diff] [blame] | 176 | (void *)packet, |
| 177 | length); |
| 178 | |
| 179 | /* Set TX Frame flags */ |
| 180 | eth->m_curTX_FD->m_opt.bf.widgetAlign = 0; |
| 181 | eth->m_curTX_FD->m_opt.bf.frameDataDir = 1; |
| 182 | eth->m_curTX_FD->m_opt.bf.littleEndian = 1; |
| 183 | eth->m_curTX_FD->m_opt.bf.macTxIrqEnbl = 1; |
| 184 | eth->m_curTX_FD->m_opt.bf.no_crc = 0; |
| 185 | eth->m_curTX_FD->m_opt.bf.no_padding = 0; |
| 186 | |
| 187 | /* Set TX Frame length */ |
| 188 | eth->m_curTX_FD->m_status.bf.len = length; |
| 189 | |
| 190 | /* Change ownership to BDMA */ |
| 191 | eth->m_curTX_FD->m_frameDataPtr.bf.owner = 1; |
| 192 | |
| 193 | /* Enable MAC and BDMA Tx control register */ |
| 194 | SET_REG( REG_BDMATXCON, ETH_BTxEn); |
| 195 | SET_REG( REG_MACTXCON, ETH_TxEn); |
| 196 | |
| 197 | /* poll on TX completion status */ |
| 198 | while ( !eth->m_curTX_FD->m_status.bf.complete) { |
| 199 | /* sleep */ |
| 200 | for ( i = 0; i < 0x10000; i ++); |
| 201 | } |
| 202 | |
| 203 | /* Change the Tx frame descriptor for next use */ |
| 204 | eth->m_curTX_FD = eth->m_curTX_FD->m_nextFD; |
| 205 | |
| 206 | return 0; |
| 207 | } |
| 208 | |
| 209 | /* Check for received packets */ |
| 210 | s32 eth_rx (void) |
| 211 | { |
| 212 | s32 nLen = 0; |
| 213 | ETH *eth = &m_eth; |
| 214 | |
| 215 | /* check if packet ready */ |
| 216 | if ( (GET_REG( REG_BDMASTAT)) & ETH_S_BRxRDF) { |
| 217 | /* process all waiting packets */ |
| 218 | while ( !eth->m_curRX_FD->m_frameDataPtr.bf.owner) { |
| 219 | nLen = eth->m_curRX_FD->m_status.bf.len; |
| 220 | /* call back u-boot -- may call eth_send() */ |
| 221 | NetReceive ((u8 *)eth->m_curRX_FD->m_frameDataPtr.ui, nLen); |
| 222 | /* set owner back to CPU */ |
| 223 | eth->m_curRX_FD->m_frameDataPtr.bf.owner = 1; |
| 224 | /* clear status */ |
| 225 | eth->m_curRX_FD->m_status.ui = 0x0; |
| 226 | /* advance to next descriptor */ |
| 227 | eth->m_curRX_FD = eth->m_curRX_FD->m_nextFD; |
| 228 | /* clear received frame bit */ |
| 229 | PUT_REG( REG_BDMASTAT, ETH_S_BRxRDF); |
| 230 | } |
| 231 | } |
| 232 | |
| 233 | return nLen; |
| 234 | } |
| 235 | |
| 236 | /* Halt ethernet engine */ |
| 237 | void eth_halt(void) |
| 238 | { |
| 239 | /* disable MAC */ |
| 240 | PUT_REG( REG_MACCON, ETH_HaltReg); |
| 241 | } |