]>
Commit | Line | Data |
---|---|---|
c041e9d2 JS |
1 | /* |
2 | * Copyright (C) 2009 BuS Elektronik GmbH & Co. KG | |
3 | * Jens Scharsig (esw@bus-elektronik.de) | |
4 | * | |
5 | * (C) Copyright 2003 | |
6 | * Author : Hamid Ikdoumi (Atmel) | |
7 | ||
1a459660 | 8 | * SPDX-License-Identifier: GPL-2.0+ |
c041e9d2 JS |
9 | */ |
10 | ||
11 | #include <common.h> | |
12 | #include <asm/io.h> | |
c041e9d2 JS |
13 | #include <asm/arch/hardware.h> |
14 | #include <asm/arch/at91_emac.h> | |
cd4de1d9 | 15 | #include <asm/arch/clk.h> |
c041e9d2 | 16 | #include <asm/arch/at91_pio.h> |
c041e9d2 JS |
17 | #include <net.h> |
18 | #include <netdev.h> | |
19 | #include <malloc.h> | |
20 | #include <miiphy.h> | |
21 | #include <linux/mii.h> | |
22 | ||
23 | #undef MII_DEBUG | |
24 | #undef ET_DEBUG | |
25 | ||
26 | #if (CONFIG_SYS_RX_ETH_BUFFER > 1024) | |
27 | #error AT91 EMAC supports max 1024 RX buffers. \ | |
28 | Please decrease the CONFIG_SYS_RX_ETH_BUFFER value | |
29 | #endif | |
30 | ||
836cd453 EB |
31 | #ifndef CONFIG_DRIVER_AT91EMAC_PHYADDR |
32 | #define CONFIG_DRIVER_AT91EMAC_PHYADDR 0 | |
33 | #endif | |
34 | ||
c041e9d2 JS |
35 | /* MDIO clock must not exceed 2.5 MHz, so enable MCK divider */ |
36 | #if (AT91C_MASTER_CLOCK > 80000000) | |
37 | #define HCLK_DIV AT91_EMAC_CFG_MCLK_64 | |
38 | #elif (AT91C_MASTER_CLOCK > 40000000) | |
39 | #define HCLK_DIV AT91_EMAC_CFG_MCLK_32 | |
40 | #elif (AT91C_MASTER_CLOCK > 20000000) | |
41 | #define HCLK_DIV AT91_EMAC_CFG_MCLK_16 | |
42 | #else | |
43 | #define HCLK_DIV AT91_EMAC_CFG_MCLK_8 | |
44 | #endif | |
45 | ||
46 | #ifdef ET_DEBUG | |
f4962066 | 47 | #define DEBUG_AT91EMAC 1 |
c041e9d2 | 48 | #else |
f4962066 | 49 | #define DEBUG_AT91EMAC 0 |
c041e9d2 JS |
50 | #endif |
51 | ||
52 | #ifdef MII_DEBUG | |
f4962066 | 53 | #define DEBUG_AT91PHY 1 |
c041e9d2 | 54 | #else |
f4962066 | 55 | #define DEBUG_AT91PHY 0 |
c041e9d2 JS |
56 | #endif |
57 | ||
58 | #ifndef CONFIG_DRIVER_AT91EMAC_QUIET | |
f4962066 | 59 | #define VERBOSEP 1 |
c041e9d2 | 60 | #else |
f4962066 | 61 | #define VERBOSEP 0 |
c041e9d2 JS |
62 | #endif |
63 | ||
64 | #define RBF_ADDR 0xfffffffc | |
65 | #define RBF_OWNER (1<<0) | |
66 | #define RBF_WRAP (1<<1) | |
67 | #define RBF_BROADCAST (1<<31) | |
68 | #define RBF_MULTICAST (1<<30) | |
69 | #define RBF_UNICAST (1<<29) | |
70 | #define RBF_EXTERNAL (1<<28) | |
6052cbab | 71 | #define RBF_UNKNOWN (1<<27) |
c041e9d2 JS |
72 | #define RBF_SIZE 0x07ff |
73 | #define RBF_LOCAL4 (1<<26) | |
74 | #define RBF_LOCAL3 (1<<25) | |
75 | #define RBF_LOCAL2 (1<<24) | |
76 | #define RBF_LOCAL1 (1<<23) | |
77 | ||
78 | #define RBF_FRAMEMAX CONFIG_SYS_RX_ETH_BUFFER | |
79 | #define RBF_FRAMELEN 0x600 | |
80 | ||
81 | typedef struct { | |
82 | unsigned long addr, size; | |
83 | } rbf_t; | |
84 | ||
85 | typedef struct { | |
86 | rbf_t rbfdt[RBF_FRAMEMAX]; | |
87 | unsigned long rbindex; | |
88 | } emac_device; | |
89 | ||
90 | void at91emac_EnableMDIO(at91_emac_t *at91mac) | |
91 | { | |
92 | /* Mac CTRL reg set for MDIO enable */ | |
93 | writel(readl(&at91mac->ctl) | AT91_EMAC_CTL_MPE, &at91mac->ctl); | |
94 | } | |
95 | ||
96 | void at91emac_DisableMDIO(at91_emac_t *at91mac) | |
97 | { | |
98 | /* Mac CTRL reg set for MDIO disable */ | |
99 | writel(readl(&at91mac->ctl) & ~AT91_EMAC_CTL_MPE, &at91mac->ctl); | |
100 | } | |
101 | ||
102 | int at91emac_read(at91_emac_t *at91mac, unsigned char addr, | |
103 | unsigned char reg, unsigned short *value) | |
104 | { | |
38bda019 | 105 | unsigned long netstat; |
c041e9d2 JS |
106 | at91emac_EnableMDIO(at91mac); |
107 | ||
108 | writel(AT91_EMAC_MAN_HIGH | AT91_EMAC_MAN_RW_R | | |
109 | AT91_EMAC_MAN_REGA(reg) | AT91_EMAC_MAN_CODE_802_3 | | |
110 | AT91_EMAC_MAN_PHYA(addr), | |
111 | &at91mac->man); | |
38bda019 AB |
112 | |
113 | do { | |
114 | netstat = readl(&at91mac->sr); | |
f4962066 | 115 | debug_cond(DEBUG_AT91PHY, "poll SR %08lx\n", netstat); |
38bda019 AB |
116 | } while (!(netstat & AT91_EMAC_SR_IDLE)); |
117 | ||
c041e9d2 JS |
118 | *value = readl(&at91mac->man) & AT91_EMAC_MAN_DATA_MASK; |
119 | ||
120 | at91emac_DisableMDIO(at91mac); | |
121 | ||
f4962066 WD |
122 | debug_cond(DEBUG_AT91PHY, |
123 | "AT91PHY read %p REG(%d)=%x\n", at91mac, reg, *value); | |
c041e9d2 JS |
124 | |
125 | return 0; | |
126 | } | |
127 | ||
128 | int at91emac_write(at91_emac_t *at91mac, unsigned char addr, | |
129 | unsigned char reg, unsigned short value) | |
130 | { | |
38bda019 | 131 | unsigned long netstat; |
f4962066 WD |
132 | debug_cond(DEBUG_AT91PHY, |
133 | "AT91PHY write %p REG(%d)=%p\n", at91mac, reg, &value); | |
c041e9d2 JS |
134 | |
135 | at91emac_EnableMDIO(at91mac); | |
136 | ||
137 | writel(AT91_EMAC_MAN_HIGH | AT91_EMAC_MAN_RW_W | | |
138 | AT91_EMAC_MAN_REGA(reg) | AT91_EMAC_MAN_CODE_802_3 | | |
139 | AT91_EMAC_MAN_PHYA(addr) | (value & AT91_EMAC_MAN_DATA_MASK), | |
140 | &at91mac->man); | |
38bda019 AB |
141 | |
142 | do { | |
143 | netstat = readl(&at91mac->sr); | |
f4962066 | 144 | debug_cond(DEBUG_AT91PHY, "poll SR %08lx\n", netstat); |
38bda019 | 145 | } while (!(netstat & AT91_EMAC_SR_IDLE)); |
c041e9d2 JS |
146 | |
147 | at91emac_DisableMDIO(at91mac); | |
38bda019 | 148 | |
c041e9d2 JS |
149 | return 0; |
150 | } | |
151 | ||
152 | #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) | |
153 | ||
d7fb9bcf | 154 | at91_emac_t *get_emacbase_by_name(const char *devname) |
c041e9d2 JS |
155 | { |
156 | struct eth_device *netdev; | |
157 | ||
158 | netdev = eth_get_dev_by_name(devname); | |
159 | return (at91_emac_t *) netdev->iobase; | |
160 | } | |
161 | ||
5a49f174 | 162 | int at91emac_mii_read(struct mii_dev *bus, int addr, int devad, int reg) |
c041e9d2 | 163 | { |
5a49f174 | 164 | unsigned short value = 0; |
c041e9d2 JS |
165 | at91_emac_t *emac; |
166 | ||
5a49f174 JH |
167 | emac = get_emacbase_by_name(bus->name); |
168 | at91emac_read(emac , addr, reg, &value); | |
169 | return value; | |
c041e9d2 JS |
170 | } |
171 | ||
172 | ||
5a49f174 JH |
173 | int at91emac_mii_write(struct mii_dev *bus, int addr, int devad, int reg, |
174 | u16 value) | |
c041e9d2 JS |
175 | { |
176 | at91_emac_t *emac; | |
177 | ||
5a49f174 | 178 | emac = get_emacbase_by_name(bus->name); |
c041e9d2 JS |
179 | at91emac_write(emac, addr, reg, value); |
180 | return 0; | |
181 | } | |
182 | ||
183 | #endif | |
184 | ||
185 | static int at91emac_phy_reset(struct eth_device *netdev) | |
186 | { | |
187 | int i; | |
188 | u16 status, adv; | |
189 | at91_emac_t *emac; | |
190 | ||
191 | emac = (at91_emac_t *) netdev->iobase; | |
192 | ||
193 | adv = ADVERTISE_CSMA | ADVERTISE_ALL; | |
836cd453 EB |
194 | at91emac_write(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR, |
195 | MII_ADVERTISE, adv); | |
f4962066 | 196 | debug_cond(VERBOSEP, "%s: Starting autonegotiation...\n", netdev->name); |
836cd453 EB |
197 | at91emac_write(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR, MII_BMCR, |
198 | (BMCR_ANENABLE | BMCR_ANRESTART)); | |
c041e9d2 | 199 | |
e63ac4cf | 200 | for (i = 0; i < 30000; i++) { |
836cd453 EB |
201 | at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR, |
202 | MII_BMSR, &status); | |
c041e9d2 JS |
203 | if (status & BMSR_ANEGCOMPLETE) |
204 | break; | |
205 | udelay(100); | |
206 | } | |
207 | ||
208 | if (status & BMSR_ANEGCOMPLETE) { | |
f4962066 WD |
209 | debug_cond(VERBOSEP, |
210 | "%s: Autonegotiation complete\n", netdev->name); | |
c041e9d2 JS |
211 | } else { |
212 | printf("%s: Autonegotiation timed out (status=0x%04x)\n", | |
213 | netdev->name, status); | |
77179067 | 214 | return -1; |
c041e9d2 JS |
215 | } |
216 | return 0; | |
217 | } | |
218 | ||
219 | static int at91emac_phy_init(struct eth_device *netdev) | |
220 | { | |
221 | u16 phy_id, status, adv, lpa; | |
222 | int media, speed, duplex; | |
223 | int i; | |
224 | at91_emac_t *emac; | |
225 | ||
226 | emac = (at91_emac_t *) netdev->iobase; | |
227 | ||
228 | /* Check if the PHY is up to snuff... */ | |
836cd453 EB |
229 | at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR, |
230 | MII_PHYSID1, &phy_id); | |
c041e9d2 JS |
231 | if (phy_id == 0xffff) { |
232 | printf("%s: No PHY present\n", netdev->name); | |
77179067 | 233 | return -1; |
c041e9d2 JS |
234 | } |
235 | ||
836cd453 EB |
236 | at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR, |
237 | MII_BMSR, &status); | |
c041e9d2 JS |
238 | |
239 | if (!(status & BMSR_LSTATUS)) { | |
240 | /* Try to re-negotiate if we don't have link already. */ | |
241 | if (at91emac_phy_reset(netdev)) | |
77179067 | 242 | return -2; |
c041e9d2 JS |
243 | |
244 | for (i = 0; i < 100000 / 100; i++) { | |
836cd453 EB |
245 | at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR, |
246 | MII_BMSR, &status); | |
c041e9d2 JS |
247 | if (status & BMSR_LSTATUS) |
248 | break; | |
249 | udelay(100); | |
250 | } | |
251 | } | |
252 | if (!(status & BMSR_LSTATUS)) { | |
f4962066 | 253 | debug_cond(VERBOSEP, "%s: link down\n", netdev->name); |
77179067 | 254 | return -3; |
c041e9d2 | 255 | } else { |
836cd453 EB |
256 | at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR, |
257 | MII_ADVERTISE, &adv); | |
258 | at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR, | |
259 | MII_LPA, &lpa); | |
c041e9d2 JS |
260 | media = mii_nway_result(lpa & adv); |
261 | speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) | |
262 | ? 1 : 0); | |
263 | duplex = (media & ADVERTISE_FULL) ? 1 : 0; | |
f4962066 | 264 | debug_cond(VERBOSEP, "%s: link up, %sMbps %s-duplex\n", |
c041e9d2 JS |
265 | netdev->name, |
266 | speed ? "100" : "10", | |
267 | duplex ? "full" : "half"); | |
268 | } | |
269 | return 0; | |
270 | } | |
271 | ||
272 | int at91emac_UpdateLinkSpeed(at91_emac_t *emac) | |
273 | { | |
274 | unsigned short stat1; | |
275 | ||
836cd453 | 276 | at91emac_read(emac, CONFIG_DRIVER_AT91EMAC_PHYADDR, MII_BMSR, &stat1); |
c041e9d2 JS |
277 | |
278 | if (!(stat1 & BMSR_LSTATUS)) /* link status up? */ | |
77179067 | 279 | return -1; |
c041e9d2 JS |
280 | |
281 | if (stat1 & BMSR_100FULL) { | |
282 | /*set Emac for 100BaseTX and Full Duplex */ | |
283 | writel(readl(&emac->cfg) | | |
284 | AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD, | |
285 | &emac->cfg); | |
286 | return 0; | |
287 | } | |
288 | ||
289 | if (stat1 & BMSR_10FULL) { | |
290 | /*set MII for 10BaseT and Full Duplex */ | |
291 | writel((readl(&emac->cfg) & | |
292 | ~(AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD) | |
293 | ) | AT91_EMAC_CFG_FD, | |
294 | &emac->cfg); | |
295 | return 0; | |
296 | } | |
297 | ||
298 | if (stat1 & BMSR_100HALF) { | |
299 | /*set MII for 100BaseTX and Half Duplex */ | |
300 | writel((readl(&emac->cfg) & | |
301 | ~(AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD) | |
302 | ) | AT91_EMAC_CFG_SPD, | |
303 | &emac->cfg); | |
304 | return 0; | |
305 | } | |
306 | ||
307 | if (stat1 & BMSR_10HALF) { | |
308 | /*set MII for 10BaseT and Half Duplex */ | |
309 | writel((readl(&emac->cfg) & | |
310 | ~(AT91_EMAC_CFG_SPD | AT91_EMAC_CFG_FD)), | |
311 | &emac->cfg); | |
312 | return 0; | |
313 | } | |
77179067 | 314 | return 0; |
c041e9d2 JS |
315 | } |
316 | ||
317 | static int at91emac_init(struct eth_device *netdev, bd_t *bd) | |
318 | { | |
319 | int i; | |
320 | u32 value; | |
321 | emac_device *dev; | |
322 | at91_emac_t *emac; | |
80733994 | 323 | at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIO; |
c041e9d2 JS |
324 | |
325 | emac = (at91_emac_t *) netdev->iobase; | |
326 | dev = (emac_device *) netdev->priv; | |
327 | ||
328 | /* PIO Disable Register */ | |
80733994 JS |
329 | value = ATMEL_PMX_AA_EMDIO | ATMEL_PMX_AA_EMDC | |
330 | ATMEL_PMX_AA_ERXER | ATMEL_PMX_AA_ERX1 | | |
331 | ATMEL_PMX_AA_ERX0 | ATMEL_PMX_AA_ECRS | | |
332 | ATMEL_PMX_AA_ETX1 | ATMEL_PMX_AA_ETX0 | | |
333 | ATMEL_PMX_AA_ETXEN | ATMEL_PMX_AA_EREFCK; | |
c041e9d2 JS |
334 | |
335 | writel(value, &pio->pioa.pdr); | |
2dc63f73 | 336 | writel(value, &pio->pioa.mux.pio2.asr); |
c041e9d2 JS |
337 | |
338 | #ifdef CONFIG_RMII | |
80733994 | 339 | value = ATMEL_PMX_BA_ERXCK; |
c041e9d2 | 340 | #else |
80733994 JS |
341 | value = ATMEL_PMX_BA_ERXCK | ATMEL_PMX_BA_ECOL | |
342 | ATMEL_PMX_BA_ERXDV | ATMEL_PMX_BA_ERX3 | | |
343 | ATMEL_PMX_BA_ERX2 | ATMEL_PMX_BA_ETXER | | |
344 | ATMEL_PMX_BA_ETX3 | ATMEL_PMX_BA_ETX2; | |
c041e9d2 JS |
345 | #endif |
346 | writel(value, &pio->piob.pdr); | |
2dc63f73 | 347 | writel(value, &pio->piob.mux.pio2.bsr); |
c041e9d2 | 348 | |
cd4de1d9 WY |
349 | at91_periph_clk_enable(ATMEL_ID_EMAC); |
350 | ||
c041e9d2 JS |
351 | writel(readl(&emac->ctl) | AT91_EMAC_CTL_CSR, &emac->ctl); |
352 | ||
c041e9d2 JS |
353 | /* Init Ethernet buffers */ |
354 | for (i = 0; i < RBF_FRAMEMAX; i++) { | |
1fd92db8 | 355 | dev->rbfdt[i].addr = (unsigned long) net_rx_packets[i]; |
c041e9d2 JS |
356 | dev->rbfdt[i].size = 0; |
357 | } | |
358 | dev->rbfdt[RBF_FRAMEMAX - 1].addr |= RBF_WRAP; | |
359 | dev->rbindex = 0; | |
360 | writel((u32) &(dev->rbfdt[0]), &emac->rbqp); | |
361 | ||
362 | writel(readl(&emac->rsr) & | |
363 | ~(AT91_EMAC_RSR_OVR | AT91_EMAC_RSR_REC | AT91_EMAC_RSR_BNA), | |
364 | &emac->rsr); | |
365 | ||
366 | value = AT91_EMAC_CFG_CAF | AT91_EMAC_CFG_NBC | | |
367 | HCLK_DIV; | |
368 | #ifdef CONFIG_RMII | |
836cd453 | 369 | value |= AT91_EMAC_CFG_RMII; |
c041e9d2 JS |
370 | #endif |
371 | writel(value, &emac->cfg); | |
372 | ||
373 | writel(readl(&emac->ctl) | AT91_EMAC_CTL_TE | AT91_EMAC_CTL_RE, | |
374 | &emac->ctl); | |
375 | ||
376 | if (!at91emac_phy_init(netdev)) { | |
377 | at91emac_UpdateLinkSpeed(emac); | |
378 | return 0; | |
379 | } | |
77179067 | 380 | return -1; |
c041e9d2 JS |
381 | } |
382 | ||
383 | static void at91emac_halt(struct eth_device *netdev) | |
384 | { | |
385 | at91_emac_t *emac; | |
386 | ||
387 | emac = (at91_emac_t *) netdev->iobase; | |
388 | writel(readl(&emac->ctl) & ~(AT91_EMAC_CTL_TE | AT91_EMAC_CTL_RE), | |
389 | &emac->ctl); | |
f4962066 | 390 | debug_cond(DEBUG_AT91EMAC, "halt MAC\n"); |
c041e9d2 JS |
391 | } |
392 | ||
9577501c | 393 | static int at91emac_send(struct eth_device *netdev, void *packet, int length) |
c041e9d2 JS |
394 | { |
395 | at91_emac_t *emac; | |
396 | ||
397 | emac = (at91_emac_t *) netdev->iobase; | |
398 | ||
399 | while (!(readl(&emac->tsr) & AT91_EMAC_TSR_BNQ)) | |
400 | ; | |
401 | writel((u32) packet, &emac->tar); | |
402 | writel(AT91_EMAC_TCR_LEN(length), &emac->tcr); | |
403 | while (AT91_EMAC_TCR_LEN(readl(&emac->tcr))) | |
404 | ; | |
f4962066 | 405 | debug_cond(DEBUG_AT91EMAC, "Send %d\n", length); |
c041e9d2 JS |
406 | writel(readl(&emac->tsr) | AT91_EMAC_TSR_COMP, &emac->tsr); |
407 | return 0; | |
408 | } | |
409 | ||
410 | static int at91emac_recv(struct eth_device *netdev) | |
411 | { | |
412 | emac_device *dev; | |
413 | at91_emac_t *emac; | |
414 | rbf_t *rbfp; | |
415 | int size; | |
416 | ||
417 | emac = (at91_emac_t *) netdev->iobase; | |
418 | dev = (emac_device *) netdev->priv; | |
419 | ||
420 | rbfp = &dev->rbfdt[dev->rbindex]; | |
421 | while (rbfp->addr & RBF_OWNER) { | |
422 | size = rbfp->size & RBF_SIZE; | |
1fd92db8 | 423 | net_process_received_packet(net_rx_packets[dev->rbindex], size); |
c041e9d2 | 424 | |
f4962066 | 425 | debug_cond(DEBUG_AT91EMAC, "Recv[%ld]: %d bytes @ %lx\n", |
c041e9d2 JS |
426 | dev->rbindex, size, rbfp->addr); |
427 | ||
428 | rbfp->addr &= ~RBF_OWNER; | |
429 | rbfp->size = 0; | |
430 | if (dev->rbindex < (RBF_FRAMEMAX-1)) | |
431 | dev->rbindex++; | |
432 | else | |
433 | dev->rbindex = 0; | |
434 | ||
435 | rbfp = &(dev->rbfdt[dev->rbindex]); | |
436 | if (!(rbfp->addr & RBF_OWNER)) | |
437 | writel(readl(&emac->rsr) | AT91_EMAC_RSR_REC, | |
438 | &emac->rsr); | |
439 | } | |
440 | ||
441 | if (readl(&emac->isr) & AT91_EMAC_IxR_RBNA) { | |
442 | /* EMAC silicon bug 41.3.1 workaround 1 */ | |
443 | writel(readl(&emac->ctl) & ~AT91_EMAC_CTL_RE, &emac->ctl); | |
444 | writel(readl(&emac->ctl) | AT91_EMAC_CTL_RE, &emac->ctl); | |
445 | dev->rbindex = 0; | |
446 | printf("%s: reset receiver (EMAC dead lock bug)\n", | |
447 | netdev->name); | |
448 | } | |
449 | return 0; | |
450 | } | |
451 | ||
409943a9 EB |
452 | static int at91emac_write_hwaddr(struct eth_device *netdev) |
453 | { | |
409943a9 | 454 | at91_emac_t *emac; |
409943a9 | 455 | emac = (at91_emac_t *) netdev->iobase; |
409943a9 | 456 | |
cd4de1d9 WY |
457 | at91_periph_clk_enable(ATMEL_ID_EMAC); |
458 | ||
f4962066 WD |
459 | debug_cond(DEBUG_AT91EMAC, |
460 | "init MAC-ADDR %02x:%02x:%02x:%02x:%02x:%02x\n", | |
2321bfe4 AB |
461 | netdev->enetaddr[5], netdev->enetaddr[4], netdev->enetaddr[3], |
462 | netdev->enetaddr[2], netdev->enetaddr[1], netdev->enetaddr[0]); | |
463 | writel( (netdev->enetaddr[0] | netdev->enetaddr[1] << 8 | | |
464 | netdev->enetaddr[2] << 16 | netdev->enetaddr[3] << 24), | |
465 | &emac->sa2l); | |
466 | writel((netdev->enetaddr[4] | netdev->enetaddr[5] << 8), &emac->sa2h); | |
f4962066 | 467 | debug_cond(DEBUG_AT91EMAC, "init MAC-ADDR %x%x\n", |
409943a9 EB |
468 | readl(&emac->sa2h), readl(&emac->sa2l)); |
469 | return 0; | |
470 | } | |
471 | ||
c041e9d2 JS |
472 | int at91emac_register(bd_t *bis, unsigned long iobase) |
473 | { | |
474 | emac_device *emac; | |
475 | emac_device *emacfix; | |
476 | struct eth_device *dev; | |
477 | ||
478 | if (iobase == 0) | |
80733994 | 479 | iobase = ATMEL_BASE_EMAC; |
c041e9d2 JS |
480 | emac = malloc(sizeof(*emac)+512); |
481 | if (emac == NULL) | |
77179067 | 482 | return -1; |
c041e9d2 JS |
483 | dev = malloc(sizeof(*dev)); |
484 | if (dev == NULL) { | |
485 | free(emac); | |
77179067 | 486 | return -1; |
c041e9d2 JS |
487 | } |
488 | /* alignment as per Errata (64 bytes) is insufficient! */ | |
489 | emacfix = (emac_device *) (((unsigned long) emac + 0x1ff) & 0xFFFFFE00); | |
490 | memset(emacfix, 0, sizeof(emac_device)); | |
491 | ||
492 | memset(dev, 0, sizeof(*dev)); | |
192bc694 | 493 | strcpy(dev->name, "emac"); |
c041e9d2 JS |
494 | dev->iobase = iobase; |
495 | dev->priv = emacfix; | |
496 | dev->init = at91emac_init; | |
497 | dev->halt = at91emac_halt; | |
498 | dev->send = at91emac_send; | |
499 | dev->recv = at91emac_recv; | |
409943a9 | 500 | dev->write_hwaddr = at91emac_write_hwaddr; |
c041e9d2 JS |
501 | |
502 | eth_register(dev); | |
503 | ||
504 | #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) | |
5a49f174 JH |
505 | int retval; |
506 | struct mii_dev *mdiodev = mdio_alloc(); | |
507 | if (!mdiodev) | |
508 | return -ENOMEM; | |
509 | strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN); | |
510 | mdiodev->read = at91emac_mii_read; | |
511 | mdiodev->write = at91emac_mii_write; | |
512 | ||
513 | retval = mdio_register(mdiodev); | |
514 | if (retval < 0) | |
515 | return retval; | |
c041e9d2 JS |
516 | #endif |
517 | return 1; | |
518 | } |