Commit ac2916a2245d999006585b6bb1e312639fa4929b
Committed by
Albert ARIBAUD
1 parent
b491d9757d
Exists in
v2017.01-smarct4x
and in
37 other branches
lpc32xx: add Ethernet support
Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
Showing 7 changed files with 659 additions and 0 deletions Side-by-side Diff
arch/arm/cpu/arm926ejs/lpc32xx/cpu.c
... | ... | @@ -5,6 +5,7 @@ |
5 | 5 | */ |
6 | 6 | |
7 | 7 | #include <common.h> |
8 | +#include <netdev.h> | |
8 | 9 | #include <asm/arch/cpu.h> |
9 | 10 | #include <asm/arch/clk.h> |
10 | 11 | #include <asm/arch/wdt.h> |
... | ... | @@ -52,6 +53,14 @@ |
52 | 53 | printf("AHB bus clock: %uMHz\n", get_hclk_clk_rate() / 1000000); |
53 | 54 | printf("Peripheral clock: %uMHz\n", get_periph_clk_rate() / 1000000); |
54 | 55 | |
56 | + return 0; | |
57 | +} | |
58 | +#endif | |
59 | + | |
60 | +#ifdef CONFIG_LPC32XX_ETH | |
61 | +int cpu_eth_init(bd_t *bis) | |
62 | +{ | |
63 | + lpc32xx_eth_initialize(bis); | |
55 | 64 | return 0; |
56 | 65 | } |
57 | 66 | #endif |
arch/arm/cpu/arm926ejs/lpc32xx/devices.c
... | ... | @@ -37,4 +37,11 @@ |
37 | 37 | writel(CLK_UART_X_DIV(1) | CLK_UART_Y_DIV(1), |
38 | 38 | &clk->u3clk + (uart_id - 3)); |
39 | 39 | } |
40 | + | |
41 | +void lpc32xx_mac_init(void) | |
42 | +{ | |
43 | + /* Enable MAC interface */ | |
44 | + writel(CLK_MAC_REG | CLK_MAC_SLAVE | CLK_MAC_MASTER | |
45 | + | CLK_MAC_MII, &clk->macclk_ctrl); | |
46 | +} |
arch/arm/include/asm/arch-lpc32xx/config.h
... | ... | @@ -52,6 +52,9 @@ |
52 | 52 | #define CONFIG_SYS_BAUDRATE_TABLE \ |
53 | 53 | { 9600, 19200, 38400, 57600, 115200, 230400, 460800 } |
54 | 54 | |
55 | +/* Ethernet */ | |
56 | +#define LPC32XX_ETH_BASE ETHERNET_BASE | |
57 | + | |
55 | 58 | /* NOR Flash */ |
56 | 59 | #if defined(CONFIG_SYS_FLASH_CFI) |
57 | 60 | #define CONFIG_FLASH_CFI_DRIVER |
arch/arm/include/asm/arch-lpc32xx/sys_proto.h
drivers/net/Makefile
... | ... | @@ -35,6 +35,7 @@ |
35 | 35 | obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o |
36 | 36 | obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o |
37 | 37 | obj-$(CONFIG_LAN91C96) += lan91c96.o |
38 | +obj-$(CONFIG_LPC32XX_ETH) += lpc32xx_eth.o | |
38 | 39 | obj-$(CONFIG_MACB) += macb.o |
39 | 40 | obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o |
40 | 41 | obj-$(CONFIG_MPC5xxx_FEC) += mpc5xxx_fec.o |
drivers/net/lpc32xx_eth.c
1 | +/* | |
2 | + * LPC32xx Ethernet MAC interface driver | |
3 | + * | |
4 | + * (C) Copyright 2014 DENX Software Engineering GmbH | |
5 | + * Written-by: Albert ARIBAUD - 3ADEV <albert.aribaud@3adev.fr> | |
6 | + * | |
7 | + * SPDX-License-Identifier: GPL-2.0+ | |
8 | + */ | |
9 | + | |
10 | +#include <common.h> | |
11 | +#include <net.h> | |
12 | +#include <malloc.h> | |
13 | +#include <miiphy.h> | |
14 | +#include <asm/io.h> | |
15 | +#include <asm/errno.h> | |
16 | +#include <asm/types.h> | |
17 | +#include <asm/system.h> | |
18 | +#include <asm/byteorder.h> | |
19 | +#include <asm/arch/cpu.h> | |
20 | +#include <asm/arch/config.h> | |
21 | + | |
22 | +/* | |
23 | + * Notes: | |
24 | + * | |
25 | + * 1. Unless specified otherwise, all references to tables or paragraphs | |
26 | + * are to UM10326, "LPC32x0 and LPC32x0/01 User manual". | |
27 | + * | |
28 | + * 2. Only bitfield masks/values which are actually used by the driver | |
29 | + * are defined. | |
30 | + */ | |
31 | + | |
32 | +/* a single RX descriptor. The controller has an array of these */ | |
33 | +struct lpc32xx_eth_rxdesc { | |
34 | + u32 packet; /* Receive packet pointer */ | |
35 | + u32 control; /* Descriptor command status */ | |
36 | +}; | |
37 | + | |
38 | +#define LPC32XX_ETH_RX_DESC_SIZE (sizeof(struct lpc32xx_eth_rxdesc)) | |
39 | + | |
40 | +/* RX control bitfields/masks (see Table 330) */ | |
41 | +#define LPC32XX_ETH_RX_CTRL_SIZE_MASK 0x000007FF | |
42 | +#define LPC32XX_ETH_RX_CTRL_UNUSED 0x7FFFF800 | |
43 | +#define LPC32XX_ETH_RX_CTRL_INTERRUPT 0x80000000 | |
44 | + | |
45 | +/* a single RX status. The controller has an array of these */ | |
46 | +struct lpc32xx_eth_rxstat { | |
47 | + u32 statusinfo; /* Transmit Descriptor status */ | |
48 | + u32 statushashcrc; /* Transmit Descriptor CRCs */ | |
49 | +}; | |
50 | + | |
51 | +#define LPC32XX_ETH_RX_STAT_SIZE (sizeof(struct lpc32xx_eth_rxstat)) | |
52 | + | |
53 | +/* RX statusinfo bitfields/masks (see Table 333) */ | |
54 | +#define RX_STAT_RXSIZE 0x000007FF | |
55 | +/* Helper: OR of all errors except RANGE */ | |
56 | +#define RX_STAT_ERRORS 0x1B800000 | |
57 | + | |
58 | +/* a single TX descriptor. The controller has an array of these */ | |
59 | +struct lpc32xx_eth_txdesc { | |
60 | + u32 packet; /* Transmit packet pointer */ | |
61 | + u32 control; /* Descriptor control */ | |
62 | +}; | |
63 | + | |
64 | +#define LPC32XX_ETH_TX_DESC_SIZE (sizeof(struct lpc32xx_eth_txdesc)) | |
65 | + | |
66 | +/* TX control bitfields/masks (see Table 335) */ | |
67 | +#define TX_CTRL_TXSIZE 0x000007FF | |
68 | +#define TX_CTRL_LAST 0x40000000 | |
69 | + | |
70 | +/* a single TX status. The controller has an array of these */ | |
71 | +struct lpc32xx_eth_txstat { | |
72 | + u32 statusinfo; /* Transmit Descriptor status */ | |
73 | +}; | |
74 | + | |
75 | +#define LPC32XX_ETH_TX_STAT_SIZE (sizeof(struct lpc32xx_eth_txstat)) | |
76 | + | |
77 | +/* Ethernet MAC interface registers (see Table 283) */ | |
78 | +struct lpc32xx_eth_registers { | |
79 | + /* MAC registers - 0x3106_0000 to 0x3106_01FC */ | |
80 | + u32 mac1; /* MAC configuration register 1 */ | |
81 | + u32 mac2; /* MAC configuration register 2 */ | |
82 | + u32 ipgt; /* Back-to-back Inter-Packet Gap reg. */ | |
83 | + u32 ipgr; /* Non-back-to-back IPG register */ | |
84 | + u32 clrt; /* Collision Window / Retry register */ | |
85 | + u32 maxf; /* Maximum Frame register */ | |
86 | + u32 supp; /* Phy Support register */ | |
87 | + u32 test; | |
88 | + u32 mcfg; /* MII management configuration reg. */ | |
89 | + u32 mcmd; /* MII management command register */ | |
90 | + u32 madr; /* MII management address register */ | |
91 | + u32 mwtd; /* MII management wite data register */ | |
92 | + u32 mrdd; /* MII management read data register */ | |
93 | + u32 mind; /* MII management indicators register */ | |
94 | + u32 reserved1[2]; | |
95 | + u32 sa0; /* Station address register 0 */ | |
96 | + u32 sa1; /* Station address register 1 */ | |
97 | + u32 sa2; /* Station address register 2 */ | |
98 | + u32 reserved2[45]; | |
99 | + /* Control registers */ | |
100 | + u32 command; | |
101 | + u32 status; | |
102 | + u32 rxdescriptor; | |
103 | + u32 rxstatus; | |
104 | + u32 rxdescriptornumber; /* actually, number MINUS ONE */ | |
105 | + u32 rxproduceindex; /* head of rx desc fifo */ | |
106 | + u32 rxconsumeindex; /* tail of rx desc fifo */ | |
107 | + u32 txdescriptor; | |
108 | + u32 txstatus; | |
109 | + u32 txdescriptornumber; /* actually, number MINUS ONE */ | |
110 | + u32 txproduceindex; /* head of rx desc fifo */ | |
111 | + u32 txconsumeindex; /* tail of rx desc fifo */ | |
112 | + u32 reserved3[10]; | |
113 | + u32 tsv0; /* Transmit status vector register 0 */ | |
114 | + u32 tsv1; /* Transmit status vector register 1 */ | |
115 | + u32 rsv; /* Receive status vector register */ | |
116 | + u32 reserved4[3]; | |
117 | + u32 flowcontrolcounter; | |
118 | + u32 flowcontrolstatus; | |
119 | + u32 reserved5[34]; | |
120 | + /* RX filter registers - 0x3106_0200 to 0x3106_0FDC */ | |
121 | + u32 rxfilterctrl; | |
122 | + u32 rxfilterwolstatus; | |
123 | + u32 rxfilterwolclear; | |
124 | + u32 reserved6; | |
125 | + u32 hashfilterl; | |
126 | + u32 hashfilterh; | |
127 | + u32 reserved7[882]; | |
128 | + /* Module control registers - 0x3106_0FE0 to 0x3106_0FF8 */ | |
129 | + u32 intstatus; /* Interrupt status register */ | |
130 | + u32 intenable; | |
131 | + u32 intclear; | |
132 | + u32 intset; | |
133 | + u32 reserved8; | |
134 | + u32 powerdown; | |
135 | + u32 reserved9; | |
136 | +}; | |
137 | + | |
138 | +/* MAC1 register bitfields/masks and offsets (see Table 283) */ | |
139 | +#define MAC1_RECV_ENABLE 0x00000001 | |
140 | +#define MAC1_PASS_ALL_RX_FRAMES 0x00000002 | |
141 | +#define MAC1_SOFT_RESET 0x00008000 | |
142 | +/* Helper: general reset */ | |
143 | +#define MAC1_RESETS 0x0000CF00 | |
144 | + | |
145 | +/* MAC2 register bitfields/masks and offsets (see Table 284) */ | |
146 | +#define MAC2_FULL_DUPLEX 0x00000001 | |
147 | +#define MAC2_CRC_ENABLE 0x00000010 | |
148 | +#define MAC2_PAD_CRC_ENABLE 0x00000020 | |
149 | + | |
150 | +/* SUPP register bitfields/masks and offsets (see Table 290) */ | |
151 | +#define SUPP_SPEED 0x00000100 | |
152 | + | |
153 | +/* MCFG register bitfields/masks and offsets (see Table 292) */ | |
154 | +#define MCFG_CLOCK_SELECT_MASK 0x0000001C | |
155 | +/* divide clock by 28 (see Table 293) */ | |
156 | +#define MCFG_CLOCK_SELECT_DIV28 0x0000001C | |
157 | + | |
158 | +/* MADR register bitfields/masks and offsets (see Table 295) */ | |
159 | +#define MADR_REG_MASK 0x0000001F | |
160 | +#define MADR_PHY_MASK 0x00001F00 | |
161 | +#define MADR_REG_OFFSET 0 | |
162 | +#define MADR_PHY_OFFSET 8 | |
163 | + | |
164 | +/* MIND register bitfields/masks (see Table 298) */ | |
165 | +#define MIND_BUSY 0x00000001 | |
166 | + | |
167 | +/* COMMAND register bitfields/masks and offsets (see Table 283) */ | |
168 | +#define COMMAND_RXENABLE 0x00000001 | |
169 | +#define COMMAND_TXENABLE 0x00000002 | |
170 | +#define COMMAND_PASSRUNTFRAME 0x00000040 | |
171 | +#define COMMAND_FULL_DUPLEX 0x00000400 | |
172 | +/* Helper: general reset */ | |
173 | +#define COMMAND_RESETS 0x0000001C | |
174 | + | |
175 | +/* STATUS register bitfields/masks and offsets (see Table 283) */ | |
176 | +#define STATUS_RXSTATUS 0x00000001 | |
177 | +#define STATUS_TXSTATUS 0x00000002 | |
178 | + | |
179 | +/* RXFILTERCTRL register bitfields/masks (see Table 319) */ | |
180 | +#define RXFILTERCTRL_ACCEPTBROADCAST 0x00000002 | |
181 | +#define RXFILTERCTRL_ACCEPTPERFECT 0x00000020 | |
182 | + | |
183 | +/* Buffers and descriptors */ | |
184 | + | |
185 | +#define ATTRS(n) __aligned(n) | |
186 | + | |
187 | +#define TX_BUF_COUNT 4 | |
188 | +#define RX_BUF_COUNT 4 | |
189 | + | |
190 | +struct lpc32xx_eth_buffers { | |
191 | + ATTRS(4) struct lpc32xx_eth_txdesc tx_desc[TX_BUF_COUNT]; | |
192 | + ATTRS(4) struct lpc32xx_eth_txstat tx_stat[TX_BUF_COUNT]; | |
193 | + ATTRS(PKTALIGN) u8 tx_buf[TX_BUF_COUNT*PKTSIZE_ALIGN]; | |
194 | + ATTRS(4) struct lpc32xx_eth_rxdesc rx_desc[RX_BUF_COUNT]; | |
195 | + ATTRS(8) struct lpc32xx_eth_rxstat rx_stat[RX_BUF_COUNT]; | |
196 | + ATTRS(PKTALIGN) u8 rx_buf[RX_BUF_COUNT*PKTSIZE_ALIGN]; | |
197 | +}; | |
198 | + | |
199 | +/* port device data struct */ | |
200 | +struct lpc32xx_eth_device { | |
201 | + struct eth_device dev; | |
202 | + struct lpc32xx_eth_registers *regs; | |
203 | + struct lpc32xx_eth_buffers *bufs; | |
204 | +}; | |
205 | + | |
206 | +#define LPC32XX_ETH_DEVICE_SIZE (sizeof(struct lpc32xx_eth_device)) | |
207 | + | |
208 | +/* generic macros */ | |
209 | +#define to_lpc32xx_eth(_d) container_of(_d, struct lpc32xx_eth_device, dev) | |
210 | + | |
211 | +/* timeout for MII polling */ | |
212 | +#define MII_TIMEOUT 10000000 | |
213 | + | |
214 | +/* limits for PHY and register addresses */ | |
215 | +#define MII_MAX_REG (MADR_REG_MASK >> MADR_REG_OFFSET) | |
216 | + | |
217 | +#define MII_MAX_PHY (MADR_PHY_MASK >> MADR_PHY_OFFSET) | |
218 | + | |
219 | +DECLARE_GLOBAL_DATA_PTR; | |
220 | + | |
221 | +#if defined(CONFIG_PHYLIB) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII) | |
222 | +/* | |
223 | + * mii_reg_read - miiphy_read callback function. | |
224 | + * | |
225 | + * Returns 16bit phy register value, or 0xffff on error | |
226 | + */ | |
227 | +static int mii_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 *data) | |
228 | +{ | |
229 | + struct eth_device *dev = eth_get_dev_by_name(devname); | |
230 | + struct lpc32xx_eth_device *dlpc32xx_eth = to_lpc32xx_eth(dev); | |
231 | + struct lpc32xx_eth_registers *regs = dlpc32xx_eth->regs; | |
232 | + u32 mind_reg; | |
233 | + u32 timeout; | |
234 | + | |
235 | + /* check parameters */ | |
236 | + if (phy_adr > MII_MAX_PHY) { | |
237 | + printf("%s:%u: Invalid PHY address %d\n", | |
238 | + __func__, __LINE__, phy_adr); | |
239 | + return -EFAULT; | |
240 | + } | |
241 | + if (reg_ofs > MII_MAX_REG) { | |
242 | + printf("%s:%u: Invalid register offset %d\n", | |
243 | + __func__, __LINE__, reg_ofs); | |
244 | + return -EFAULT; | |
245 | + } | |
246 | + | |
247 | + /* write the phy and reg addressse into the MII address reg */ | |
248 | + writel((phy_adr << MADR_PHY_OFFSET) | (reg_ofs << MADR_REG_OFFSET), | |
249 | + ®s->madr); | |
250 | + | |
251 | + /* write 1 to the MII command register to cause a read */ | |
252 | + writel(1, ®s->mcmd); | |
253 | + | |
254 | + /* wait till the MII is not busy */ | |
255 | + timeout = MII_TIMEOUT; | |
256 | + do { | |
257 | + /* read MII indicators register */ | |
258 | + mind_reg = readl(®s->mind); | |
259 | + if (--timeout == 0) | |
260 | + break; | |
261 | + } while (mind_reg & MIND_BUSY); | |
262 | + | |
263 | + /* write 0 to the MII command register to finish the read */ | |
264 | + writel(0, ®s->mcmd); | |
265 | + | |
266 | + if (timeout == 0) { | |
267 | + printf("%s:%u: MII busy timeout\n", __func__, __LINE__); | |
268 | + return -EFAULT; | |
269 | + } | |
270 | + | |
271 | + *data = (u16) readl(®s->mrdd); | |
272 | + | |
273 | + debug("%s:(adr %d, off %d) => %04x\n", __func__, phy_adr, | |
274 | + reg_ofs, *data); | |
275 | + | |
276 | + return 0; | |
277 | +} | |
278 | + | |
279 | +/* | |
280 | + * mii_reg_write - imiiphy_write callback function. | |
281 | + * | |
282 | + * Returns 0 if write succeed, -EINVAL on bad parameters | |
283 | + * -ETIME on timeout | |
284 | + */ | |
285 | +static int mii_reg_write(const char *devname, u8 phy_adr, u8 reg_ofs, u16 data) | |
286 | +{ | |
287 | + struct eth_device *dev = eth_get_dev_by_name(devname); | |
288 | + struct lpc32xx_eth_device *dlpc32xx_eth = to_lpc32xx_eth(dev); | |
289 | + struct lpc32xx_eth_registers *regs = dlpc32xx_eth->regs; | |
290 | + u32 mind_reg; | |
291 | + u32 timeout; | |
292 | + | |
293 | + /* check parameters */ | |
294 | + if (phy_adr > MII_MAX_PHY) { | |
295 | + printf("%s:%u: Invalid PHY address %d\n", | |
296 | + __func__, __LINE__, phy_adr); | |
297 | + return -EFAULT; | |
298 | + } | |
299 | + if (reg_ofs > MII_MAX_REG) { | |
300 | + printf("%s:%u: Invalid register offset %d\n", | |
301 | + __func__, __LINE__, reg_ofs); | |
302 | + return -EFAULT; | |
303 | + } | |
304 | + | |
305 | + /* wait till the MII is not busy */ | |
306 | + timeout = MII_TIMEOUT; | |
307 | + do { | |
308 | + /* read MII indicators register */ | |
309 | + mind_reg = readl(®s->mind); | |
310 | + if (--timeout == 0) | |
311 | + break; | |
312 | + } while (mind_reg & MIND_BUSY); | |
313 | + | |
314 | + if (timeout == 0) { | |
315 | + printf("%s:%u: MII busy timeout\n", __func__, | |
316 | + __LINE__); | |
317 | + return -EFAULT; | |
318 | + } | |
319 | + | |
320 | + /* write the phy and reg addressse into the MII address reg */ | |
321 | + writel((phy_adr << MADR_PHY_OFFSET) | (reg_ofs << MADR_REG_OFFSET), | |
322 | + ®s->madr); | |
323 | + | |
324 | + /* write data to the MII write register */ | |
325 | + writel(data, ®s->mwtd); | |
326 | + | |
327 | + /*debug("%s:(adr %d, off %d) <= %04x\n", __func__, phy_adr, | |
328 | + reg_ofs, data);*/ | |
329 | + | |
330 | + return 0; | |
331 | +} | |
332 | +#endif | |
333 | + | |
334 | +#if defined(CONFIG_PHYLIB) | |
335 | +int lpc32xx_eth_phy_read(struct mii_dev *bus, int phy_addr, int dev_addr, | |
336 | + int reg_addr) | |
337 | +{ | |
338 | + u16 data; | |
339 | + int ret; | |
340 | + ret = mii_reg_read(bus->name, phy_addr, reg_addr, &data); | |
341 | + if (ret) | |
342 | + return ret; | |
343 | + return data; | |
344 | +} | |
345 | + | |
346 | +int lpc32xx_eth_phy_write(struct mii_dev *bus, int phy_addr, int dev_addr, | |
347 | + int reg_addr, u16 data) | |
348 | +{ | |
349 | + return mii_reg_write(bus->name, phy_addr, reg_addr, data); | |
350 | +} | |
351 | +#endif | |
352 | + | |
353 | +/* | |
354 | + * Locate buffers in SRAM at 0x00001000 to avoid cache issues and | |
355 | + * maximize throughput. | |
356 | + */ | |
357 | + | |
358 | +#define LPC32XX_ETH_BUFS 0x00001000 | |
359 | + | |
360 | +static struct lpc32xx_eth_device lpc32xx_eth = { | |
361 | + .regs = (struct lpc32xx_eth_registers *)LPC32XX_ETH_BASE, | |
362 | + .bufs = (struct lpc32xx_eth_buffers *)LPC32XX_ETH_BUFS | |
363 | +}; | |
364 | + | |
365 | +#define TX_TIMEOUT 10000 | |
366 | + | |
367 | +static int lpc32xx_eth_send(struct eth_device *dev, void *dataptr, int datasize) | |
368 | +{ | |
369 | + struct lpc32xx_eth_device *lpc32xx_eth_device = | |
370 | + container_of(dev, struct lpc32xx_eth_device, dev); | |
371 | + struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs; | |
372 | + struct lpc32xx_eth_buffers *bufs = lpc32xx_eth_device->bufs; | |
373 | + int timeout, tx_index; | |
374 | + | |
375 | + /* time out if transmit descriptor array remains full too long */ | |
376 | + timeout = TX_TIMEOUT; | |
377 | + while ((readl(®s->status) & STATUS_TXSTATUS) && | |
378 | + (readl(®s->txconsumeindex) | |
379 | + == readl(®s->txproduceindex))) { | |
380 | + if (timeout-- == 0) | |
381 | + return -1; | |
382 | + } | |
383 | + | |
384 | + /* determine next transmit packet index to use */ | |
385 | + tx_index = readl(®s->txproduceindex); | |
386 | + | |
387 | + /* set up transmit packet */ | |
388 | + writel((u32)dataptr, &bufs->tx_desc[tx_index].packet); | |
389 | + writel(TX_CTRL_LAST | ((datasize - 1) & TX_CTRL_TXSIZE), | |
390 | + &bufs->tx_desc[tx_index].control); | |
391 | + writel(0, &bufs->tx_stat[tx_index].statusinfo); | |
392 | + | |
393 | + /* pass transmit packet to DMA engine */ | |
394 | + tx_index = (tx_index + 1) % TX_BUF_COUNT; | |
395 | + writel(tx_index, ®s->txproduceindex); | |
396 | + | |
397 | + /* transmission succeeded */ | |
398 | + return 0; | |
399 | +} | |
400 | + | |
401 | +#define RX_TIMEOUT 1000000 | |
402 | + | |
403 | +static int lpc32xx_eth_recv(struct eth_device *dev) | |
404 | +{ | |
405 | + struct lpc32xx_eth_device *lpc32xx_eth_device = | |
406 | + container_of(dev, struct lpc32xx_eth_device, dev); | |
407 | + struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs; | |
408 | + struct lpc32xx_eth_buffers *bufs = lpc32xx_eth_device->bufs; | |
409 | + int timeout, rx_index; | |
410 | + | |
411 | + /* time out if receive descriptor array remains empty too long */ | |
412 | + timeout = RX_TIMEOUT; | |
413 | + while (readl(®s->rxproduceindex) == readl(®s->rxconsumeindex)) { | |
414 | + if (timeout-- == 0) | |
415 | + return -1; | |
416 | + } | |
417 | + | |
418 | + /* determine next receive packet index to use */ | |
419 | + rx_index = readl(®s->rxconsumeindex); | |
420 | + | |
421 | + /* if data was valid, pass it on */ | |
422 | + if (!(bufs->rx_stat[rx_index].statusinfo & RX_STAT_ERRORS)) | |
423 | + NetReceive(&(bufs->rx_buf[rx_index*PKTSIZE_ALIGN]), | |
424 | + (bufs->rx_stat[rx_index].statusinfo | |
425 | + & RX_STAT_RXSIZE) + 1); | |
426 | + | |
427 | + /* pass receive slot back to DMA engine */ | |
428 | + rx_index = (rx_index + 1) % RX_BUF_COUNT; | |
429 | + writel(rx_index, ®s->rxconsumeindex); | |
430 | + | |
431 | + /* reception successful */ | |
432 | + return 0; | |
433 | +} | |
434 | + | |
435 | +static int lpc32xx_eth_write_hwaddr(struct eth_device *dev) | |
436 | +{ | |
437 | + struct lpc32xx_eth_device *lpc32xx_eth_device = | |
438 | + container_of(dev, struct lpc32xx_eth_device, dev); | |
439 | + struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs; | |
440 | + | |
441 | + /* Save station address */ | |
442 | + writel((unsigned long) (dev->enetaddr[0] | | |
443 | + (dev->enetaddr[1] << 8)), ®s->sa2); | |
444 | + writel((unsigned long) (dev->enetaddr[2] | | |
445 | + (dev->enetaddr[3] << 8)), ®s->sa1); | |
446 | + writel((unsigned long) (dev->enetaddr[4] | | |
447 | + (dev->enetaddr[5] << 8)), ®s->sa0); | |
448 | + | |
449 | + return 0; | |
450 | +} | |
451 | + | |
452 | +static int lpc32xx_eth_init(struct eth_device *dev) | |
453 | +{ | |
454 | + struct lpc32xx_eth_device *lpc32xx_eth_device = | |
455 | + container_of(dev, struct lpc32xx_eth_device, dev); | |
456 | + struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs; | |
457 | + struct lpc32xx_eth_buffers *bufs = lpc32xx_eth_device->bufs; | |
458 | + int index; | |
459 | + | |
460 | + /* Release SOFT reset to let MII talk to PHY */ | |
461 | + clrbits_le32(®s->mac1, MAC1_SOFT_RESET); | |
462 | + | |
463 | + /* Configure Full/Half Duplex mode */ | |
464 | + if (miiphy_duplex(dev->name, CONFIG_PHY_ADDR) == FULL) { | |
465 | + setbits_le32(®s->mac2, MAC2_FULL_DUPLEX); | |
466 | + setbits_le32(®s->command, COMMAND_FULL_DUPLEX); | |
467 | + writel(0x15, ®s->ipgt); | |
468 | + } else { | |
469 | + writel(0x12, ®s->ipgt); | |
470 | + } | |
471 | + | |
472 | + /* Configure 100MBit/10MBit mode */ | |
473 | + if (miiphy_speed(dev->name, CONFIG_PHY_ADDR) == _100BASET) | |
474 | + writel(SUPP_SPEED, ®s->supp); | |
475 | + else | |
476 | + writel(0, ®s->supp); | |
477 | + | |
478 | + /* Initial MAC initialization */ | |
479 | + writel(MAC1_PASS_ALL_RX_FRAMES, ®s->mac1); | |
480 | + writel(MAC2_PAD_CRC_ENABLE | MAC2_CRC_ENABLE, ®s->mac2); | |
481 | + writel(PKTSIZE_ALIGN, ®s->maxf); | |
482 | + | |
483 | + /* Retries: 15 (0xF). Collision window: 57 (0x37). */ | |
484 | + writel(0x370F, ®s->clrt); | |
485 | + | |
486 | + /* Set IP gap pt 2 to default 0x12 but pt 1 to non-default 0 */ | |
487 | + writel(0x0012, ®s->ipgr); | |
488 | + | |
489 | + /* pass runt (smaller than 64 bytes) frames */ | |
490 | + writel(COMMAND_PASSRUNTFRAME, ®s->command); | |
491 | + | |
492 | + /* Save station address */ | |
493 | + writel((unsigned long) (dev->enetaddr[0] | | |
494 | + (dev->enetaddr[1] << 8)), ®s->sa2); | |
495 | + writel((unsigned long) (dev->enetaddr[2] | | |
496 | + (dev->enetaddr[3] << 8)), ®s->sa1); | |
497 | + writel((unsigned long) (dev->enetaddr[4] | | |
498 | + (dev->enetaddr[5] << 8)), ®s->sa0); | |
499 | + | |
500 | + /* set up transmit buffers */ | |
501 | + for (index = 0; index < TX_BUF_COUNT; index++) { | |
502 | + bufs->tx_desc[index].control = 0; | |
503 | + bufs->tx_stat[index].statusinfo = 0; | |
504 | + } | |
505 | + writel((u32)(&bufs->tx_desc), (u32 *)®s->txdescriptor); | |
506 | + writel((u32)(&bufs->tx_stat), ®s->txstatus); | |
507 | + writel(TX_BUF_COUNT-1, ®s->txdescriptornumber); | |
508 | + | |
509 | + /* set up receive buffers */ | |
510 | + for (index = 0; index < RX_BUF_COUNT; index++) { | |
511 | + bufs->rx_desc[index].packet = | |
512 | + (u32) (bufs->rx_buf+index*PKTSIZE_ALIGN); | |
513 | + bufs->rx_desc[index].control = PKTSIZE_ALIGN - 1; | |
514 | + bufs->rx_stat[index].statusinfo = 0; | |
515 | + bufs->rx_stat[index].statushashcrc = 0; | |
516 | + } | |
517 | + writel((u32)(&bufs->rx_desc), ®s->rxdescriptor); | |
518 | + writel((u32)(&bufs->rx_stat), ®s->rxstatus); | |
519 | + writel(RX_BUF_COUNT-1, ®s->rxdescriptornumber); | |
520 | + | |
521 | + /* Enable broadcast and matching address packets */ | |
522 | + writel(RXFILTERCTRL_ACCEPTBROADCAST | | |
523 | + RXFILTERCTRL_ACCEPTPERFECT, ®s->rxfilterctrl); | |
524 | + | |
525 | + /* Clear and disable interrupts */ | |
526 | + writel(0xFFFF, ®s->intclear); | |
527 | + writel(0, ®s->intenable); | |
528 | + | |
529 | + /* Enable receive and transmit mode of MAC ethernet core */ | |
530 | + setbits_le32(®s->command, COMMAND_RXENABLE | COMMAND_TXENABLE); | |
531 | + setbits_le32(®s->mac1, MAC1_RECV_ENABLE); | |
532 | + | |
533 | + /* | |
534 | + * Perform a 'dummy' first send to work around Ethernet.1 | |
535 | + * erratum (see ES_LPC3250 rev. 9 dated 1 June 2011). | |
536 | + * Use zeroed "index" variable as the dummy. | |
537 | + */ | |
538 | + | |
539 | + index = 0; | |
540 | + lpc32xx_eth_send(dev, &index, 4); | |
541 | + | |
542 | + return 0; | |
543 | +} | |
544 | + | |
545 | +static int lpc32xx_eth_halt(struct eth_device *dev) | |
546 | +{ | |
547 | + struct lpc32xx_eth_device *lpc32xx_eth_device = | |
548 | + container_of(dev, struct lpc32xx_eth_device, dev); | |
549 | + struct lpc32xx_eth_registers *regs = lpc32xx_eth_device->regs; | |
550 | + | |
551 | + /* Reset all MAC logic */ | |
552 | + writel(MAC1_RESETS, ®s->mac1); | |
553 | + writel(COMMAND_RESETS, ®s->command); | |
554 | + /* Let reset condition settle */ | |
555 | + udelay(2000); | |
556 | + | |
557 | + return 0; | |
558 | +} | |
559 | + | |
560 | +#if defined(CONFIG_PHYLIB) | |
561 | +int lpc32xx_eth_phylib_init(struct eth_device *dev, int phyid) | |
562 | +{ | |
563 | + struct mii_dev *bus; | |
564 | + struct phy_device *phydev; | |
565 | + int ret; | |
566 | + | |
567 | + bus = mdio_alloc(); | |
568 | + if (!bus) { | |
569 | + printf("mdio_alloc failed\n"); | |
570 | + return -ENOMEM; | |
571 | + } | |
572 | + bus->read = lpc32xx_eth_phy_read; | |
573 | + bus->write = lpc32xx_eth_phy_write; | |
574 | + sprintf(bus->name, dev->name); | |
575 | + | |
576 | + ret = mdio_register(bus); | |
577 | + if (ret) { | |
578 | + printf("mdio_register failed\n"); | |
579 | + free(bus); | |
580 | + return -ENOMEM; | |
581 | + } | |
582 | + | |
583 | + phydev = phy_connect(bus, phyid, dev, PHY_INTERFACE_MODE_MII); | |
584 | + if (!phydev) { | |
585 | + printf("phy_connect failed\n"); | |
586 | + return -ENODEV; | |
587 | + } | |
588 | + | |
589 | + phy_config(phydev); | |
590 | + phy_startup(phydev); | |
591 | + | |
592 | + return 0; | |
593 | +} | |
594 | +#endif | |
595 | + | |
596 | +int lpc32xx_eth_initialize(bd_t *bis) | |
597 | +{ | |
598 | + struct eth_device *dev = &lpc32xx_eth.dev; | |
599 | + struct lpc32xx_eth_registers *regs = lpc32xx_eth.regs; | |
600 | + | |
601 | + /* | |
602 | + * Set RMII management clock rate. With HCLK at 104 MHz and | |
603 | + * a divider of 28, this will be 3.72 MHz. | |
604 | + */ | |
605 | + | |
606 | + writel(MCFG_CLOCK_SELECT_DIV28, ®s->mcfg); | |
607 | + | |
608 | + /* Reset all MAC logic */ | |
609 | + writel(MAC1_RESETS, ®s->mac1); | |
610 | + writel(COMMAND_RESETS, ®s->command); | |
611 | + | |
612 | + /* wait 10 ms for the whole I/F to reset */ | |
613 | + udelay(10000); | |
614 | + | |
615 | + /* must be less than sizeof(dev->name) */ | |
616 | + strcpy(dev->name, "eth0"); | |
617 | + | |
618 | + dev->init = (void *)lpc32xx_eth_init; | |
619 | + dev->halt = (void *)lpc32xx_eth_halt; | |
620 | + dev->send = (void *)lpc32xx_eth_send; | |
621 | + dev->recv = (void *)lpc32xx_eth_recv; | |
622 | + dev->write_hwaddr = (void *)lpc32xx_eth_write_hwaddr; | |
623 | + | |
624 | + /* Release SOFT reset to let MII talk to PHY */ | |
625 | + clrbits_le32(®s->mac1, MAC1_SOFT_RESET); | |
626 | + | |
627 | + /* register driver before talking to phy */ | |
628 | + eth_register(dev); | |
629 | + | |
630 | +#if defined(CONFIG_PHYLIB) | |
631 | + lpc32xx_eth_phylib_init(dev, 0); | |
632 | +#elif defined(CONFIG_MII) || defined(CONFIG_CMD_MII) | |
633 | + miiphy_register(dev->name, mii_reg_read, mii_reg_write); | |
634 | +#endif | |
635 | + | |
636 | + return 0; | |
637 | +} |
include/netdev.h
... | ... | @@ -57,6 +57,7 @@ |
57 | 57 | void gt6426x_eth_initialize(bd_t *bis); |
58 | 58 | int ks8851_mll_initialize(u8 dev_num, int base_addr); |
59 | 59 | int lan91c96_initialize(u8 dev_num, int base_addr); |
60 | +int lpc32xx_eth_initialize(bd_t *bis); | |
60 | 61 | int macb_eth_initialize(int id, void *regs, unsigned int phy_addr); |
61 | 62 | int mcdmafec_initialize(bd_t *bis); |
62 | 63 | int mcffec_initialize(bd_t *bis); |