blob: 78337731e1fd7a71e02ec772561e9806abfd96b0 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Christophe Leroy907208c2017-07-06 10:23:22 +02002/*
3 * (C) Copyright 2000
4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
Christophe Leroy907208c2017-07-06 10:23:22 +02005 */
6
7#include <common.h>
8#include <command.h>
Simon Glassdb41d652019-12-28 10:45:07 -07009#include <hang.h>
Christophe Leroy907208c2017-07-06 10:23:22 +020010#include <malloc.h>
11#include <net.h>
Christophe Leroy08dd9882017-07-13 15:10:08 +020012#include <netdev.h>
Christophe Leroy18f8d4c2018-03-16 17:20:43 +010013#include <asm/cpm_8xx.h>
Simon Glass401d1c42020-10-30 21:38:53 -060014#include <asm/global_data.h>
Christophe Leroyba3da732017-07-06 10:33:13 +020015#include <asm/io.h>
Simon Glassc05ed002020-05-10 11:40:11 -060016#include <linux/delay.h>
Christophe Leroy907208c2017-07-06 10:23:22 +020017
18#include <phy.h>
Simon Glass68a6aa82019-11-14 12:57:31 -070019#include <linux/mii.h>
Christophe Leroy907208c2017-07-06 10:23:22 +020020
21DECLARE_GLOBAL_DATA_PTR;
22
Christophe Leroy907208c2017-07-06 10:23:22 +020023/* define WANT_MII when MII support is required */
24#if defined(CONFIG_SYS_DISCOVER_PHY) || defined(CONFIG_FEC1_PHY) || defined(CONFIG_FEC2_PHY)
25#define WANT_MII
26#else
27#undef WANT_MII
28#endif
29
30#if defined(WANT_MII)
31#include <miiphy.h>
32
33#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
34#error "CONFIG_MII has to be defined!"
35#endif
36
37#endif
38
39#if defined(CONFIG_RMII) && !defined(WANT_MII)
40#error RMII support is unusable without a working PHY.
41#endif
42
43#ifdef CONFIG_SYS_DISCOVER_PHY
Christophe Leroy81844ac2022-05-12 15:48:51 +020044static int mii_discover_phy(struct udevice *dev);
Christophe Leroy907208c2017-07-06 10:23:22 +020045#endif
46
47int fec8xx_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg);
48int fec8xx_miiphy_write(struct mii_dev *bus, int addr, int devad, int reg,
49 u16 value);
50
51static struct ether_fcc_info_s
52{
53 int ether_index;
54 int fecp_offset;
55 int phy_addr;
56 int actual_phy_addr;
57 int initialized;
58}
59 ether_fcc_info[] = {
60#if defined(CONFIG_ETHER_ON_FEC1)
61 {
62 0,
63 offsetof(immap_t, im_cpm.cp_fec1),
Christophe Leroy907208c2017-07-06 10:23:22 +020064 CONFIG_FEC1_PHY,
Christophe Leroy907208c2017-07-06 10:23:22 +020065 -1,
66 0,
67
68 },
69#endif
70#if defined(CONFIG_ETHER_ON_FEC2)
71 {
72 1,
73 offsetof(immap_t, im_cpm.cp_fec2),
Christophe Leroy907208c2017-07-06 10:23:22 +020074 CONFIG_FEC2_PHY,
Christophe Leroy907208c2017-07-06 10:23:22 +020075 -1,
76 0,
77 },
78#endif
79};
80
81/* Ethernet Transmit and Receive Buffers */
82#define DBUF_LENGTH 1520
83
84#define TX_BUF_CNT 2
85
86#define TOUT_LOOP 100
87
88#define PKT_MAXBUF_SIZE 1518
89#define PKT_MINBUF_SIZE 64
90#define PKT_MAXBLR_SIZE 1520
91
92#ifdef __GNUC__
Christophe Leroy70fd0712017-07-06 10:33:17 +020093static char txbuf[DBUF_LENGTH] __aligned(8);
Christophe Leroy907208c2017-07-06 10:23:22 +020094#else
95#error txbuf must be aligned.
96#endif
97
98static uint rxIdx; /* index of the current RX buffer */
99static uint txIdx; /* index of the current TX buffer */
100
101/*
102 * FEC Ethernet Tx and Rx buffer descriptors allocated at the
103 * immr->udata_bd address on Dual-Port RAM
104 * Provide for Double Buffering
105 */
106
Christophe Leroyba3da732017-07-06 10:33:13 +0200107struct common_buf_desc {
Christophe Leroy70fd0712017-07-06 10:33:17 +0200108 cbd_t rxbd[PKTBUFSRX]; /* Rx BD */
109 cbd_t txbd[TX_BUF_CNT]; /* Tx BD */
Christophe Leroyba3da732017-07-06 10:33:13 +0200110};
Christophe Leroy907208c2017-07-06 10:23:22 +0200111
Christophe Leroyba3da732017-07-06 10:33:13 +0200112static struct common_buf_desc __iomem *rtx;
Christophe Leroy907208c2017-07-06 10:23:22 +0200113
Christophe Leroy907208c2017-07-06 10:23:22 +0200114#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
115static void __mii_init(void);
116#endif
117
Christophe Leroy81844ac2022-05-12 15:48:51 +0200118static int fec_probe(struct udevice *dev)
Christophe Leroy907208c2017-07-06 10:23:22 +0200119{
Christophe Leroy81844ac2022-05-12 15:48:51 +0200120 struct ether_fcc_info_s *efis = dev_get_priv(dev);
121 int index = dev_get_driver_data(dev);
Christophe Leroy907208c2017-07-06 10:23:22 +0200122 int i;
123
124 for (i = 0; i < ARRAY_SIZE(ether_fcc_info); i++) {
Christophe Leroy81844ac2022-05-12 15:48:51 +0200125 if (ether_fcc_info[i].ether_index != index)
126 continue;
Christophe Leroy907208c2017-07-06 10:23:22 +0200127
Christophe Leroy81844ac2022-05-12 15:48:51 +0200128 memcpy(efis, &ether_fcc_info[i], sizeof(*efis));
Christophe Leroy907208c2017-07-06 10:23:22 +0200129
Christophe Leroy907208c2017-07-06 10:23:22 +0200130 efis->actual_phy_addr = -1;
131
Christophe Leroy907208c2017-07-06 10:23:22 +0200132#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
133 int retval;
134 struct mii_dev *mdiodev = mdio_alloc();
135 if (!mdiodev)
136 return -ENOMEM;
Vladimir Oltean56b9cae2021-09-27 14:21:53 +0300137 strlcpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
Christophe Leroy907208c2017-07-06 10:23:22 +0200138 mdiodev->read = fec8xx_miiphy_read;
139 mdiodev->write = fec8xx_miiphy_write;
140
141 retval = mdio_register(mdiodev);
142 if (retval < 0)
143 return retval;
144#endif
145 }
Christophe Leroy81844ac2022-05-12 15:48:51 +0200146 return 0;
Christophe Leroy907208c2017-07-06 10:23:22 +0200147}
148
Christophe Leroy81844ac2022-05-12 15:48:51 +0200149static int fec_send(struct udevice *dev, void *packet, int length)
Christophe Leroy907208c2017-07-06 10:23:22 +0200150{
151 int j, rc;
Christophe Leroy81844ac2022-05-12 15:48:51 +0200152 struct ether_fcc_info_s *efis = dev_get_priv(dev);
Christophe Leroyba3da732017-07-06 10:33:13 +0200153 fec_t __iomem *fecp =
154 (fec_t __iomem *)(CONFIG_SYS_IMMR + efis->fecp_offset);
Christophe Leroy907208c2017-07-06 10:23:22 +0200155
156 /* section 16.9.23.3
157 * Wait for ready
158 */
159 j = 0;
Christophe Leroyba3da732017-07-06 10:33:13 +0200160 while ((in_be16(&rtx->txbd[txIdx].cbd_sc) & BD_ENET_TX_READY) &&
161 (j < TOUT_LOOP)) {
Christophe Leroy907208c2017-07-06 10:23:22 +0200162 udelay(1);
163 j++;
164 }
Christophe Leroy70fd0712017-07-06 10:33:17 +0200165 if (j >= TOUT_LOOP)
Christophe Leroy907208c2017-07-06 10:23:22 +0200166 printf("TX not ready\n");
Christophe Leroy907208c2017-07-06 10:23:22 +0200167
Christophe Leroyba3da732017-07-06 10:33:13 +0200168 out_be32(&rtx->txbd[txIdx].cbd_bufaddr, (uint)packet);
169 out_be16(&rtx->txbd[txIdx].cbd_datlen, length);
170 setbits_be16(&rtx->txbd[txIdx].cbd_sc,
171 BD_ENET_TX_READY | BD_ENET_TX_LAST);
Christophe Leroy907208c2017-07-06 10:23:22 +0200172
173 /* Activate transmit Buffer Descriptor polling */
Christophe Leroyba3da732017-07-06 10:33:13 +0200174 /* Descriptor polling active */
175 out_be32(&fecp->fec_x_des_active, 0x01000000);
Christophe Leroy907208c2017-07-06 10:23:22 +0200176
177 j = 0;
Christophe Leroyba3da732017-07-06 10:33:13 +0200178 while ((in_be16(&rtx->txbd[txIdx].cbd_sc) & BD_ENET_TX_READY) &&
179 (j < TOUT_LOOP)) {
Christophe Leroy907208c2017-07-06 10:23:22 +0200180 udelay(1);
181 j++;
182 }
Christophe Leroy70fd0712017-07-06 10:33:17 +0200183 if (j >= TOUT_LOOP)
Christophe Leroy907208c2017-07-06 10:23:22 +0200184 printf("TX timeout\n");
Christophe Leroy70fd0712017-07-06 10:33:17 +0200185
Christophe Leroy907208c2017-07-06 10:23:22 +0200186 /* return only status bits */;
Christophe Leroyba3da732017-07-06 10:33:13 +0200187 rc = in_be16(&rtx->txbd[txIdx].cbd_sc) & BD_ENET_TX_STATS;
Christophe Leroy907208c2017-07-06 10:23:22 +0200188
189 txIdx = (txIdx + 1) % TX_BUF_CNT;
190
191 return rc;
192}
193
Christophe Leroy81844ac2022-05-12 15:48:51 +0200194static int fec_recv(struct udevice *dev, int flags, uchar **packetp)
Christophe Leroy907208c2017-07-06 10:23:22 +0200195{
Christophe Leroy907208c2017-07-06 10:23:22 +0200196 int length;
197
Christophe Leroy81844ac2022-05-12 15:48:51 +0200198 /* section 16.9.23.2 */
199 if (in_be16(&rtx->rxbd[rxIdx].cbd_sc) & BD_ENET_RX_EMPTY)
200 return -EAGAIN;
Christophe Leroy907208c2017-07-06 10:23:22 +0200201
Christophe Leroy81844ac2022-05-12 15:48:51 +0200202 length = in_be16(&rtx->rxbd[rxIdx].cbd_datlen);
Christophe Leroy907208c2017-07-06 10:23:22 +0200203
Christophe Leroy81844ac2022-05-12 15:48:51 +0200204 if (!(in_be16(&rtx->rxbd[rxIdx].cbd_sc) & 0x003f)) {
205 uchar *rx = net_rx_packets[rxIdx];
Christophe Leroy907208c2017-07-06 10:23:22 +0200206
207#if defined(CONFIG_CMD_CDP)
Christophe Leroy81844ac2022-05-12 15:48:51 +0200208 if ((rx[0] & 1) != 0 &&
209 memcmp((uchar *)rx, net_bcast_ethaddr, 6) != 0 &&
210 !is_cdp_packet((uchar *)rx))
211 return 0;
Christophe Leroy907208c2017-07-06 10:23:22 +0200212#endif
Christophe Leroy81844ac2022-05-12 15:48:51 +0200213 *packetp = rx;
Christophe Leroy907208c2017-07-06 10:23:22 +0200214
Christophe Leroy81844ac2022-05-12 15:48:51 +0200215 return length - 4;
216 } else {
217 return 0;
218 }
219}
Christophe Leroy907208c2017-07-06 10:23:22 +0200220
Christophe Leroy81844ac2022-05-12 15:48:51 +0200221static int fec_free_pkt(struct udevice *dev, uchar *packet, int length)
222{
223 struct ether_fcc_info_s *efis = dev_get_priv(dev);
224 fec_t __iomem *fecp =
225 (fec_t __iomem *)(CONFIG_SYS_IMMR + efis->fecp_offset);
Christophe Leroy907208c2017-07-06 10:23:22 +0200226
Christophe Leroy81844ac2022-05-12 15:48:51 +0200227 /* Give the buffer back to the FEC. */
228 out_be16(&rtx->rxbd[rxIdx].cbd_datlen, 0);
229
230 /* wrap around buffer index when necessary */
231 if ((rxIdx + 1) >= PKTBUFSRX) {
232 out_be16(&rtx->rxbd[PKTBUFSRX - 1].cbd_sc,
233 BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY);
234 rxIdx = 0;
235 } else {
236 out_be16(&rtx->rxbd[rxIdx].cbd_sc, BD_ENET_RX_EMPTY);
237 rxIdx++;
Christophe Leroy907208c2017-07-06 10:23:22 +0200238 }
239
Christophe Leroy81844ac2022-05-12 15:48:51 +0200240 /* Try to fill Buffer Descriptors */
241 /* Descriptor polling active */
242 out_be32(&fecp->fec_r_des_active, 0x01000000);
243
244 return 0;
Christophe Leroy907208c2017-07-06 10:23:22 +0200245}
246
247/**************************************************************
248 *
249 * FEC Ethernet Initialization Routine
250 *
251 *************************************************************/
252
253#define FEC_ECNTRL_PINMUX 0x00000004
254#define FEC_ECNTRL_ETHER_EN 0x00000002
255#define FEC_ECNTRL_RESET 0x00000001
256
257#define FEC_RCNTRL_BC_REJ 0x00000010
258#define FEC_RCNTRL_PROM 0x00000008
259#define FEC_RCNTRL_MII_MODE 0x00000004
260#define FEC_RCNTRL_DRT 0x00000002
261#define FEC_RCNTRL_LOOP 0x00000001
262
263#define FEC_TCNTRL_FDEN 0x00000004
264#define FEC_TCNTRL_HBC 0x00000002
265#define FEC_TCNTRL_GTS 0x00000001
266
267#define FEC_RESET_DELAY 50
268
269#if defined(CONFIG_RMII)
270
Christophe Leroy81844ac2022-05-12 15:48:51 +0200271static inline void fec_10Mbps(struct udevice *dev)
Christophe Leroy907208c2017-07-06 10:23:22 +0200272{
Christophe Leroy81844ac2022-05-12 15:48:51 +0200273 struct ether_fcc_info_s *efis = dev_get_priv(dev);
Christophe Leroy907208c2017-07-06 10:23:22 +0200274 int fecidx = efis->ether_index;
275 uint mask = (fecidx == 0) ? 0x0000010 : 0x0000008;
Christophe Leroyba3da732017-07-06 10:33:13 +0200276 immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
Christophe Leroy907208c2017-07-06 10:23:22 +0200277
278 if ((unsigned int)fecidx >= 2)
279 hang();
280
Christophe Leroyba3da732017-07-06 10:33:13 +0200281 setbits_be32(&immr->im_cpm.cp_cptr, mask);
Christophe Leroy907208c2017-07-06 10:23:22 +0200282}
283
Christophe Leroy81844ac2022-05-12 15:48:51 +0200284static inline void fec_100Mbps(struct udevice *dev)
Christophe Leroy907208c2017-07-06 10:23:22 +0200285{
Christophe Leroy81844ac2022-05-12 15:48:51 +0200286 struct ether_fcc_info_s *efis = dev_get_priv(dev);
Christophe Leroy907208c2017-07-06 10:23:22 +0200287 int fecidx = efis->ether_index;
288 uint mask = (fecidx == 0) ? 0x0000010 : 0x0000008;
Christophe Leroyba3da732017-07-06 10:33:13 +0200289 immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
Christophe Leroy907208c2017-07-06 10:23:22 +0200290
291 if ((unsigned int)fecidx >= 2)
292 hang();
293
Christophe Leroyba3da732017-07-06 10:33:13 +0200294 clrbits_be32(&immr->im_cpm.cp_cptr, mask);
Christophe Leroy907208c2017-07-06 10:23:22 +0200295}
296
297#endif
298
Christophe Leroy81844ac2022-05-12 15:48:51 +0200299static inline void fec_full_duplex(struct udevice *dev)
Christophe Leroy907208c2017-07-06 10:23:22 +0200300{
Christophe Leroy81844ac2022-05-12 15:48:51 +0200301 struct ether_fcc_info_s *efis = dev_get_priv(dev);
Christophe Leroyba3da732017-07-06 10:33:13 +0200302 fec_t __iomem *fecp =
303 (fec_t __iomem *)(CONFIG_SYS_IMMR + efis->fecp_offset);
Christophe Leroy907208c2017-07-06 10:23:22 +0200304
Christophe Leroyba3da732017-07-06 10:33:13 +0200305 clrbits_be32(&fecp->fec_r_cntrl, FEC_RCNTRL_DRT);
306 setbits_be32(&fecp->fec_x_cntrl, FEC_TCNTRL_FDEN); /* FD enable */
Christophe Leroy907208c2017-07-06 10:23:22 +0200307}
308
Christophe Leroy81844ac2022-05-12 15:48:51 +0200309static inline void fec_half_duplex(struct udevice *dev)
Christophe Leroy907208c2017-07-06 10:23:22 +0200310{
Christophe Leroy81844ac2022-05-12 15:48:51 +0200311 struct ether_fcc_info_s *efis = dev_get_priv(dev);
Christophe Leroyba3da732017-07-06 10:33:13 +0200312 fec_t __iomem *fecp =
313 (fec_t __iomem *)(CONFIG_SYS_IMMR + efis->fecp_offset);
Christophe Leroy907208c2017-07-06 10:23:22 +0200314
Christophe Leroyba3da732017-07-06 10:33:13 +0200315 setbits_be32(&fecp->fec_r_cntrl, FEC_RCNTRL_DRT);
316 clrbits_be32(&fecp->fec_x_cntrl, FEC_TCNTRL_FDEN); /* FD disable */
Christophe Leroy907208c2017-07-06 10:23:22 +0200317}
318
319static void fec_pin_init(int fecidx)
320{
Masahiro Yamadab75d8dc2020-06-26 15:13:33 +0900321 struct bd_info *bd = gd->bd;
Christophe Leroyba3da732017-07-06 10:33:13 +0200322 immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
Christophe Leroy907208c2017-07-06 10:23:22 +0200323
324 /*
325 * Set MII speed to 2.5 MHz or slightly below.
326 *
327 * According to the MPC860T (Rev. D) Fast ethernet controller user
328 * manual (6.2.14),
329 * the MII management interface clock must be less than or equal
330 * to 2.5 MHz.
331 * This MDC frequency is equal to system clock / (2 * MII_SPEED).
332 * Then MII_SPEED = system_clock / 2 * 2,5 MHz.
333 *
334 * All MII configuration is done via FEC1 registers:
335 */
Christophe Leroyba3da732017-07-06 10:33:13 +0200336 out_be32(&immr->im_cpm.cp_fec1.fec_mii_speed,
337 ((bd->bi_intfreq + 4999999) / 5000000) << 1);
Christophe Leroy907208c2017-07-06 10:23:22 +0200338
Christophe Leroyb1e41d12017-07-06 10:33:21 +0200339#if defined(CONFIG_MPC885) && defined(WANT_MII)
Christophe Leroy907208c2017-07-06 10:23:22 +0200340 /* use MDC for MII */
Christophe Leroyba3da732017-07-06 10:33:13 +0200341 setbits_be16(&immr->im_ioport.iop_pdpar, 0x0080);
342 clrbits_be16(&immr->im_ioport.iop_pddir, 0x0080);
Christophe Leroy907208c2017-07-06 10:23:22 +0200343#endif
344
345 if (fecidx == 0) {
346#if defined(CONFIG_ETHER_ON_FEC1)
347
Christophe Leroyb1e41d12017-07-06 10:33:21 +0200348#if defined(CONFIG_MPC885) /* MPC87x/88x have got 2 FECs and different pinout */
Christophe Leroy907208c2017-07-06 10:23:22 +0200349
350#if !defined(CONFIG_RMII)
351
Christophe Leroyba3da732017-07-06 10:33:13 +0200352 setbits_be16(&immr->im_ioport.iop_papar, 0xf830);
353 setbits_be16(&immr->im_ioport.iop_padir, 0x0830);
354 clrbits_be16(&immr->im_ioport.iop_padir, 0xf000);
Christophe Leroy907208c2017-07-06 10:23:22 +0200355
Christophe Leroyba3da732017-07-06 10:33:13 +0200356 setbits_be32(&immr->im_cpm.cp_pbpar, 0x00001001);
357 clrbits_be32(&immr->im_cpm.cp_pbdir, 0x00001001);
Christophe Leroy907208c2017-07-06 10:23:22 +0200358
Christophe Leroyba3da732017-07-06 10:33:13 +0200359 setbits_be16(&immr->im_ioport.iop_pcpar, 0x000c);
360 clrbits_be16(&immr->im_ioport.iop_pcdir, 0x000c);
Christophe Leroy907208c2017-07-06 10:23:22 +0200361
Christophe Leroyba3da732017-07-06 10:33:13 +0200362 setbits_be32(&immr->im_cpm.cp_pepar, 0x00000003);
363 setbits_be32(&immr->im_cpm.cp_pedir, 0x00000003);
364 clrbits_be32(&immr->im_cpm.cp_peso, 0x00000003);
Christophe Leroy907208c2017-07-06 10:23:22 +0200365
Christophe Leroyba3da732017-07-06 10:33:13 +0200366 clrbits_be32(&immr->im_cpm.cp_cptr, 0x00000100);
Christophe Leroy907208c2017-07-06 10:23:22 +0200367
368#else
369
370#if !defined(CONFIG_FEC1_PHY_NORXERR)
Christophe Leroyba3da732017-07-06 10:33:13 +0200371 setbits_be16(&immr->im_ioport.iop_papar, 0x1000);
372 clrbits_be16(&immr->im_ioport.iop_padir, 0x1000);
Christophe Leroy907208c2017-07-06 10:23:22 +0200373#endif
Christophe Leroyba3da732017-07-06 10:33:13 +0200374 setbits_be16(&immr->im_ioport.iop_papar, 0xe810);
375 setbits_be16(&immr->im_ioport.iop_padir, 0x0810);
376 clrbits_be16(&immr->im_ioport.iop_padir, 0xe000);
Christophe Leroy907208c2017-07-06 10:23:22 +0200377
Christophe Leroyba3da732017-07-06 10:33:13 +0200378 setbits_be32(&immr->im_cpm.cp_pbpar, 0x00000001);
379 clrbits_be32(&immr->im_cpm.cp_pbdir, 0x00000001);
Christophe Leroy907208c2017-07-06 10:23:22 +0200380
Christophe Leroyba3da732017-07-06 10:33:13 +0200381 setbits_be32(&immr->im_cpm.cp_cptr, 0x00000100);
382 clrbits_be32(&immr->im_cpm.cp_cptr, 0x00000050);
Christophe Leroy907208c2017-07-06 10:23:22 +0200383
384#endif /* !CONFIG_RMII */
385
386#else
387 /*
388 * Configure all of port D for MII.
389 */
Christophe Leroyba3da732017-07-06 10:33:13 +0200390 out_be16(&immr->im_ioport.iop_pdpar, 0x1fff);
391 out_be16(&immr->im_ioport.iop_pddir, 0x1fff);
Christophe Leroy53193a42017-07-07 10:16:42 +0200392
393#if defined(CONFIG_TARGET_MCR3000)
394 out_be16(&immr->im_ioport.iop_papar, 0xBBFF);
395 out_be16(&immr->im_ioport.iop_padir, 0x04F0);
396 out_be16(&immr->im_ioport.iop_paodr, 0x0000);
397
398 out_be32(&immr->im_cpm.cp_pbpar, 0x000133FF);
399 out_be32(&immr->im_cpm.cp_pbdir, 0x0003BF0F);
400 out_be16(&immr->im_cpm.cp_pbodr, 0x0000);
401
402 out_be16(&immr->im_ioport.iop_pcpar, 0x0400);
403 out_be16(&immr->im_ioport.iop_pcdir, 0x0080);
404 out_be16(&immr->im_ioport.iop_pcso , 0x0D53);
405 out_be16(&immr->im_ioport.iop_pcint, 0x0000);
406
407 out_be16(&immr->im_ioport.iop_pdpar, 0x03FE);
408 out_be16(&immr->im_ioport.iop_pddir, 0x1C09);
409
410 setbits_be32(&immr->im_ioport.utmode, 0x80);
411#endif
Christophe Leroy907208c2017-07-06 10:23:22 +0200412#endif
413
414#endif /* CONFIG_ETHER_ON_FEC1 */
415 } else if (fecidx == 1) {
Christophe Leroy907208c2017-07-06 10:23:22 +0200416#if defined(CONFIG_ETHER_ON_FEC2)
417
Christophe Leroyb1e41d12017-07-06 10:33:21 +0200418#if defined(CONFIG_MPC885) /* MPC87x/88x have got 2 FECs and different pinout */
Christophe Leroy907208c2017-07-06 10:23:22 +0200419
420#if !defined(CONFIG_RMII)
Christophe Leroyba3da732017-07-06 10:33:13 +0200421 setbits_be32(&immr->im_cpm.cp_pepar, 0x0003fffc);
422 setbits_be32(&immr->im_cpm.cp_pedir, 0x0003fffc);
423 clrbits_be32(&immr->im_cpm.cp_peso, 0x000087fc);
424 setbits_be32(&immr->im_cpm.cp_peso, 0x00037800);
Christophe Leroy907208c2017-07-06 10:23:22 +0200425
Christophe Leroyba3da732017-07-06 10:33:13 +0200426 clrbits_be32(&immr->im_cpm.cp_cptr, 0x00000080);
Christophe Leroy907208c2017-07-06 10:23:22 +0200427#else
428
429#if !defined(CONFIG_FEC2_PHY_NORXERR)
Christophe Leroyba3da732017-07-06 10:33:13 +0200430 setbits_be32(&immr->im_cpm.cp_pepar, 0x00000010);
431 setbits_be32(&immr->im_cpm.cp_pedir, 0x00000010);
432 clrbits_be32(&immr->im_cpm.cp_peso, 0x00000010);
Christophe Leroy907208c2017-07-06 10:23:22 +0200433#endif
Christophe Leroyba3da732017-07-06 10:33:13 +0200434 setbits_be32(&immr->im_cpm.cp_pepar, 0x00039620);
435 setbits_be32(&immr->im_cpm.cp_pedir, 0x00039620);
436 setbits_be32(&immr->im_cpm.cp_peso, 0x00031000);
437 clrbits_be32(&immr->im_cpm.cp_peso, 0x00008620);
Christophe Leroy907208c2017-07-06 10:23:22 +0200438
Christophe Leroyba3da732017-07-06 10:33:13 +0200439 setbits_be32(&immr->im_cpm.cp_cptr, 0x00000080);
440 clrbits_be32(&immr->im_cpm.cp_cptr, 0x00000028);
Christophe Leroy907208c2017-07-06 10:23:22 +0200441#endif /* CONFIG_RMII */
442
Christophe Leroyb1e41d12017-07-06 10:33:21 +0200443#endif /* CONFIG_MPC885 */
Christophe Leroy907208c2017-07-06 10:23:22 +0200444
445#endif /* CONFIG_ETHER_ON_FEC2 */
Christophe Leroy907208c2017-07-06 10:23:22 +0200446 }
447}
448
Christophe Leroyba3da732017-07-06 10:33:13 +0200449static int fec_reset(fec_t __iomem *fecp)
Christophe Leroy907208c2017-07-06 10:23:22 +0200450{
451 int i;
452
453 /* Whack a reset.
454 * A delay is required between a reset of the FEC block and
455 * initialization of other FEC registers because the reset takes
456 * some time to complete. If you don't delay, subsequent writes
457 * to FEC registers might get killed by the reset routine which is
458 * still in progress.
459 */
460
Christophe Leroyba3da732017-07-06 10:33:13 +0200461 out_be32(&fecp->fec_ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET);
462 for (i = 0; (in_be32(&fecp->fec_ecntrl) & FEC_ECNTRL_RESET) &&
463 (i < FEC_RESET_DELAY); ++i)
Christophe Leroy70fd0712017-07-06 10:33:17 +0200464 udelay(1);
Christophe Leroyba3da732017-07-06 10:33:13 +0200465
Christophe Leroy907208c2017-07-06 10:23:22 +0200466 if (i == FEC_RESET_DELAY)
467 return -1;
468
469 return 0;
470}
471
Christophe Leroy81844ac2022-05-12 15:48:51 +0200472static int fec_start(struct udevice *dev)
Christophe Leroy907208c2017-07-06 10:23:22 +0200473{
Christophe Leroy81844ac2022-05-12 15:48:51 +0200474 struct eth_pdata *plat = dev_get_plat(dev);
475 struct ether_fcc_info_s *efis = dev_get_priv(dev);
Christophe Leroyba3da732017-07-06 10:33:13 +0200476 immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
477 fec_t __iomem *fecp =
478 (fec_t __iomem *)(CONFIG_SYS_IMMR + efis->fecp_offset);
Christophe Leroy907208c2017-07-06 10:23:22 +0200479 int i;
480
481#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
482 /* the MII interface is connected to FEC1
483 * so for the miiphy_xxx function to work we must
484 * call mii_init since fec_halt messes the thing up
485 */
486 if (efis->ether_index != 0)
487 __mii_init();
488#endif
489
490 if (fec_reset(fecp) < 0)
Christophe Leroy70fd0712017-07-06 10:33:17 +0200491 printf("FEC_RESET_DELAY timeout\n");
Christophe Leroy907208c2017-07-06 10:23:22 +0200492
493 /* We use strictly polling mode only
494 */
Christophe Leroyba3da732017-07-06 10:33:13 +0200495 out_be32(&fecp->fec_imask, 0);
Christophe Leroy907208c2017-07-06 10:23:22 +0200496
497 /* Clear any pending interrupt
498 */
Christophe Leroyba3da732017-07-06 10:33:13 +0200499 out_be32(&fecp->fec_ievent, 0xffc0);
Christophe Leroy907208c2017-07-06 10:23:22 +0200500
501 /* No need to set the IVEC register */
502
503 /* Set station address
504 */
Christophe Leroy81844ac2022-05-12 15:48:51 +0200505#define ea plat->enetaddr
Christophe Leroyba3da732017-07-06 10:33:13 +0200506 out_be32(&fecp->fec_addr_low, (ea[0] << 24) | (ea[1] << 16) |
507 (ea[2] << 8) | ea[3]);
508 out_be16(&fecp->fec_addr_high, (ea[4] << 8) | ea[5]);
Christophe Leroy907208c2017-07-06 10:23:22 +0200509#undef ea
510
511#if defined(CONFIG_CMD_CDP)
512 /*
513 * Turn on multicast address hash table
514 */
Christophe Leroyba3da732017-07-06 10:33:13 +0200515 out_be32(&fecp->fec_hash_table_high, 0xffffffff);
516 out_be32(&fecp->fec_hash_table_low, 0xffffffff);
Christophe Leroy907208c2017-07-06 10:23:22 +0200517#else
518 /* Clear multicast address hash table
519 */
Christophe Leroyba3da732017-07-06 10:33:13 +0200520 out_be32(&fecp->fec_hash_table_high, 0);
521 out_be32(&fecp->fec_hash_table_low, 0);
Christophe Leroy907208c2017-07-06 10:23:22 +0200522#endif
523
524 /* Set maximum receive buffer size.
525 */
Christophe Leroyba3da732017-07-06 10:33:13 +0200526 out_be32(&fecp->fec_r_buff_size, PKT_MAXBLR_SIZE);
Christophe Leroy907208c2017-07-06 10:23:22 +0200527
528 /* Set maximum frame length
529 */
Christophe Leroyba3da732017-07-06 10:33:13 +0200530 out_be32(&fecp->fec_r_hash, PKT_MAXBUF_SIZE);
Christophe Leroy907208c2017-07-06 10:23:22 +0200531
532 /*
Christophe Leroy70fd0712017-07-06 10:33:17 +0200533 * Setup Buffers and Buffer Descriptors
Christophe Leroy907208c2017-07-06 10:23:22 +0200534 */
535 rxIdx = 0;
536 txIdx = 0;
537
538 if (!rtx)
Christophe Leroyba3da732017-07-06 10:33:13 +0200539 rtx = (struct common_buf_desc __iomem *)
540 (immr->im_cpm.cp_dpmem + CPM_FEC_BASE);
Christophe Leroy907208c2017-07-06 10:23:22 +0200541 /*
542 * Setup Receiver Buffer Descriptors (13.14.24.18)
543 * Settings:
544 * Empty, Wrap
545 */
546 for (i = 0; i < PKTBUFSRX; i++) {
Christophe Leroyba3da732017-07-06 10:33:13 +0200547 out_be16(&rtx->rxbd[i].cbd_sc, BD_ENET_RX_EMPTY);
548 out_be16(&rtx->rxbd[i].cbd_datlen, 0); /* Reset */
549 out_be32(&rtx->rxbd[i].cbd_bufaddr, (uint)net_rx_packets[i]);
Christophe Leroy907208c2017-07-06 10:23:22 +0200550 }
Christophe Leroyba3da732017-07-06 10:33:13 +0200551 setbits_be16(&rtx->rxbd[PKTBUFSRX - 1].cbd_sc, BD_ENET_RX_WRAP);
Christophe Leroy907208c2017-07-06 10:23:22 +0200552
553 /*
554 * Setup Ethernet Transmitter Buffer Descriptors (13.14.24.19)
555 * Settings:
556 * Last, Tx CRC
557 */
558 for (i = 0; i < TX_BUF_CNT; i++) {
Christophe Leroyba3da732017-07-06 10:33:13 +0200559 out_be16(&rtx->txbd[i].cbd_sc, BD_ENET_TX_LAST | BD_ENET_TX_TC);
560 out_be16(&rtx->txbd[i].cbd_datlen, 0); /* Reset */
561 out_be32(&rtx->txbd[i].cbd_bufaddr, (uint)txbuf);
Christophe Leroy907208c2017-07-06 10:23:22 +0200562 }
Christophe Leroyba3da732017-07-06 10:33:13 +0200563 setbits_be16(&rtx->txbd[TX_BUF_CNT - 1].cbd_sc, BD_ENET_TX_WRAP);
Christophe Leroy907208c2017-07-06 10:23:22 +0200564
565 /* Set receive and transmit descriptor base
566 */
Christophe Leroyba3da732017-07-06 10:33:13 +0200567 out_be32(&fecp->fec_r_des_start, (__force unsigned int)rtx->rxbd);
568 out_be32(&fecp->fec_x_des_start, (__force unsigned int)rtx->txbd);
Christophe Leroy907208c2017-07-06 10:23:22 +0200569
570 /* Enable MII mode
571 */
572 /* Half duplex mode */
Christophe Leroyba3da732017-07-06 10:33:13 +0200573 out_be32(&fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE | FEC_RCNTRL_DRT);
574 out_be32(&fecp->fec_x_cntrl, 0);
Christophe Leroy907208c2017-07-06 10:23:22 +0200575
576 /* Enable big endian and don't care about SDMA FC.
577 */
Christophe Leroyba3da732017-07-06 10:33:13 +0200578 out_be32(&fecp->fec_fun_code, 0x78000000);
Christophe Leroy907208c2017-07-06 10:23:22 +0200579
580 /*
581 * Setup the pin configuration of the FEC
582 */
Christophe Leroy70fd0712017-07-06 10:33:17 +0200583 fec_pin_init(efis->ether_index);
Christophe Leroy907208c2017-07-06 10:23:22 +0200584
585 rxIdx = 0;
586 txIdx = 0;
587
588 /*
589 * Now enable the transmit and receive processing
590 */
Christophe Leroyba3da732017-07-06 10:33:13 +0200591 out_be32(&fecp->fec_ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
Christophe Leroy907208c2017-07-06 10:23:22 +0200592
593 if (efis->phy_addr == -1) {
594#ifdef CONFIG_SYS_DISCOVER_PHY
595 /*
596 * wait for the PHY to wake up after reset
597 */
Christophe Leroy70fd0712017-07-06 10:33:17 +0200598 efis->actual_phy_addr = mii_discover_phy(dev);
Christophe Leroy907208c2017-07-06 10:23:22 +0200599
600 if (efis->actual_phy_addr == -1) {
Christophe Leroy70fd0712017-07-06 10:33:17 +0200601 printf("Unable to discover phy!\n");
Christophe Leroy907208c2017-07-06 10:23:22 +0200602 return -1;
603 }
604#else
605 efis->actual_phy_addr = -1;
606#endif
607 } else {
608 efis->actual_phy_addr = efis->phy_addr;
609 }
610
611#if defined(CONFIG_MII) && defined(CONFIG_RMII)
612 /*
613 * adapt the RMII speed to the speed of the phy
614 */
Christophe Leroy70fd0712017-07-06 10:33:17 +0200615 if (miiphy_speed(dev->name, efis->actual_phy_addr) == _100BASET)
616 fec_100Mbps(dev);
617 else
618 fec_10Mbps(dev);
Christophe Leroy907208c2017-07-06 10:23:22 +0200619#endif
620
621#if defined(CONFIG_MII)
622 /*
623 * adapt to the half/full speed settings
624 */
Christophe Leroy70fd0712017-07-06 10:33:17 +0200625 if (miiphy_duplex(dev->name, efis->actual_phy_addr) == FULL)
626 fec_full_duplex(dev);
627 else
628 fec_half_duplex(dev);
Christophe Leroy907208c2017-07-06 10:23:22 +0200629#endif
630
631 /* And last, try to fill Rx Buffer Descriptors */
Christophe Leroyba3da732017-07-06 10:33:13 +0200632 /* Descriptor polling active */
633 out_be32(&fecp->fec_r_des_active, 0x01000000);
Christophe Leroy907208c2017-07-06 10:23:22 +0200634
635 efis->initialized = 1;
636
637 return 0;
638}
639
640
Christophe Leroy81844ac2022-05-12 15:48:51 +0200641static void fec_stop(struct udevice *dev)
Christophe Leroy907208c2017-07-06 10:23:22 +0200642{
Christophe Leroy81844ac2022-05-12 15:48:51 +0200643 struct ether_fcc_info_s *efis = dev_get_priv(dev);
Christophe Leroyba3da732017-07-06 10:33:13 +0200644 fec_t __iomem *fecp =
645 (fec_t __iomem *)(CONFIG_SYS_IMMR + efis->fecp_offset);
Christophe Leroy907208c2017-07-06 10:23:22 +0200646 int i;
647
648 /* avoid halt if initialized; mii gets stuck otherwise */
649 if (!efis->initialized)
650 return;
651
652 /* Whack a reset.
653 * A delay is required between a reset of the FEC block and
654 * initialization of other FEC registers because the reset takes
655 * some time to complete. If you don't delay, subsequent writes
656 * to FEC registers might get killed by the reset routine which is
657 * still in progress.
658 */
659
Christophe Leroyba3da732017-07-06 10:33:13 +0200660 out_be32(&fecp->fec_ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET);
661 for (i = 0; (in_be32(&fecp->fec_ecntrl) & FEC_ECNTRL_RESET) &&
662 (i < FEC_RESET_DELAY); ++i)
Christophe Leroy70fd0712017-07-06 10:33:17 +0200663 udelay(1);
Christophe Leroyba3da732017-07-06 10:33:13 +0200664
Christophe Leroy907208c2017-07-06 10:23:22 +0200665 if (i == FEC_RESET_DELAY) {
Christophe Leroy70fd0712017-07-06 10:33:17 +0200666 printf("FEC_RESET_DELAY timeout\n");
Christophe Leroy907208c2017-07-06 10:23:22 +0200667 return;
668 }
669
670 efis->initialized = 0;
671}
672
673#if defined(CONFIG_SYS_DISCOVER_PHY) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
674
675/* Make MII read/write commands for the FEC.
676*/
677
678#define mk_mii_read(ADDR, REG) (0x60020000 | ((ADDR << 23) | \
679 (REG & 0x1f) << 18))
680
681#define mk_mii_write(ADDR, REG, VAL) (0x50020000 | ((ADDR << 23) | \
682 (REG & 0x1f) << 18) | \
683 (VAL & 0xffff))
684
685/* Interrupt events/masks.
686*/
687#define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */
688#define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */
689#define FEC_ENET_BABT ((uint)0x20000000) /* Babbling transmitter */
690#define FEC_ENET_GRA ((uint)0x10000000) /* Graceful stop complete */
691#define FEC_ENET_TXF ((uint)0x08000000) /* Full frame transmitted */
692#define FEC_ENET_TXB ((uint)0x04000000) /* A buffer was transmitted */
693#define FEC_ENET_RXF ((uint)0x02000000) /* Full frame received */
694#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */
695#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */
696#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */
697
698/* send command to phy using mii, wait for result */
699static uint
700mii_send(uint mii_cmd)
701{
702 uint mii_reply;
Christophe Leroyba3da732017-07-06 10:33:13 +0200703 fec_t __iomem *ep;
Christophe Leroy907208c2017-07-06 10:23:22 +0200704 int cnt;
Christophe Leroyba3da732017-07-06 10:33:13 +0200705 immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
Christophe Leroy907208c2017-07-06 10:23:22 +0200706
Christophe Leroyba3da732017-07-06 10:33:13 +0200707 ep = &immr->im_cpm.cp_fec;
Christophe Leroy907208c2017-07-06 10:23:22 +0200708
Christophe Leroyba3da732017-07-06 10:33:13 +0200709 out_be32(&ep->fec_mii_data, mii_cmd); /* command to phy */
Christophe Leroy907208c2017-07-06 10:23:22 +0200710
711 /* wait for mii complete */
712 cnt = 0;
Christophe Leroyba3da732017-07-06 10:33:13 +0200713 while (!(in_be32(&ep->fec_ievent) & FEC_ENET_MII)) {
Christophe Leroy907208c2017-07-06 10:23:22 +0200714 if (++cnt > 1000) {
715 printf("mii_send STUCK!\n");
716 break;
717 }
718 }
Christophe Leroyba3da732017-07-06 10:33:13 +0200719 mii_reply = in_be32(&ep->fec_mii_data); /* result from phy */
720 out_be32(&ep->fec_ievent, FEC_ENET_MII); /* clear MII complete */
Christophe Leroy70fd0712017-07-06 10:33:17 +0200721 return mii_reply & 0xffff; /* data read from phy */
Christophe Leroy907208c2017-07-06 10:23:22 +0200722}
723#endif
724
725#if defined(CONFIG_SYS_DISCOVER_PHY)
Christophe Leroy81844ac2022-05-12 15:48:51 +0200726static int mii_discover_phy(struct udevice *dev)
Christophe Leroy907208c2017-07-06 10:23:22 +0200727{
728#define MAX_PHY_PASSES 11
729 uint phyno;
730 int pass;
731 uint phytype;
732 int phyaddr;
733
734 phyaddr = -1; /* didn't find a PHY yet */
735 for (pass = 1; pass <= MAX_PHY_PASSES && phyaddr < 0; ++pass) {
736 if (pass > 1) {
737 /* PHY may need more time to recover from reset.
738 * The LXT970 needs 50ms typical, no maximum is
739 * specified, so wait 10ms before try again.
740 * With 11 passes this gives it 100ms to wake up.
741 */
742 udelay(10000); /* wait 10ms */
743 }
744 for (phyno = 0; phyno < 32 && phyaddr < 0; ++phyno) {
745 phytype = mii_send(mk_mii_read(phyno, MII_PHYSID2));
746 if (phytype != 0xffff) {
747 phyaddr = phyno;
748 phytype |= mii_send(mk_mii_read(phyno,
749 MII_PHYSID1)) << 16;
750 }
751 }
752 }
Christophe Leroy70fd0712017-07-06 10:33:17 +0200753 if (phyaddr < 0)
Christophe Leroy907208c2017-07-06 10:23:22 +0200754 printf("No PHY device found.\n");
Christophe Leroy70fd0712017-07-06 10:33:17 +0200755
Christophe Leroy907208c2017-07-06 10:23:22 +0200756 return phyaddr;
757}
758#endif /* CONFIG_SYS_DISCOVER_PHY */
759
760#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && !defined(CONFIG_BITBANGMII)
761
762/****************************************************************************
763 * mii_init -- Initialize the MII via FEC 1 for MII command without ethernet
764 * This function is a subset of eth_init
765 ****************************************************************************
766 */
767static void __mii_init(void)
768{
Christophe Leroyba3da732017-07-06 10:33:13 +0200769 immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR;
770 fec_t __iomem *fecp = &immr->im_cpm.cp_fec;
Christophe Leroy907208c2017-07-06 10:23:22 +0200771
772 if (fec_reset(fecp) < 0)
Christophe Leroy70fd0712017-07-06 10:33:17 +0200773 printf("FEC_RESET_DELAY timeout\n");
Christophe Leroy907208c2017-07-06 10:23:22 +0200774
775 /* We use strictly polling mode only
776 */
Christophe Leroyba3da732017-07-06 10:33:13 +0200777 out_be32(&fecp->fec_imask, 0);
Christophe Leroy907208c2017-07-06 10:23:22 +0200778
779 /* Clear any pending interrupt
780 */
Christophe Leroyba3da732017-07-06 10:33:13 +0200781 out_be32(&fecp->fec_ievent, 0xffc0);
Christophe Leroy907208c2017-07-06 10:23:22 +0200782
783 /* Now enable the transmit and receive processing
784 */
Christophe Leroyba3da732017-07-06 10:33:13 +0200785 out_be32(&fecp->fec_ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
Christophe Leroy907208c2017-07-06 10:23:22 +0200786}
787
Christophe Leroy70fd0712017-07-06 10:33:17 +0200788void mii_init(void)
Christophe Leroy907208c2017-07-06 10:23:22 +0200789{
790 int i;
791
792 __mii_init();
793
794 /* Setup the pin configuration of the FEC(s)
795 */
796 for (i = 0; i < ARRAY_SIZE(ether_fcc_info); i++)
797 fec_pin_init(ether_fcc_info[i].ether_index);
798}
799
800/*****************************************************************************
801 * Read and write a MII PHY register, routines used by MII Utilities
802 *
803 * FIXME: These routines are expected to return 0 on success, but mii_send
804 * does _not_ return an error code. Maybe 0xFFFF means error, i.e.
805 * no PHY connected...
806 * For now always return 0.
807 * FIXME: These routines only work after calling eth_init() at least once!
808 * Otherwise they hang in mii_send() !!! Sorry!
809 *****************************************************************************/
810
811int fec8xx_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg)
812{
813 unsigned short value = 0;
814 short rdreg; /* register working value */
815
816 rdreg = mii_send(mk_mii_read(addr, reg));
817
818 value = rdreg;
819 return value;
820}
821
822int fec8xx_miiphy_write(struct mii_dev *bus, int addr, int devad, int reg,
823 u16 value)
824{
825 (void)mii_send(mk_mii_write(addr, reg, value));
826
827 return 0;
828}
829#endif
Christophe Leroy81844ac2022-05-12 15:48:51 +0200830
831static const struct eth_ops fec_ops = {
832 .start = fec_start,
833 .send = fec_send,
834 .recv = fec_recv,
835 .stop = fec_stop,
836 .free_pkt = fec_free_pkt,
837};
838
839static const struct udevice_id fec_ids[] = {
840#ifdef CONFIG_ETHER_ON_FEC1
841 {
842 .compatible = "fsl,pq1-fec1",
843 .data = 0,
844 },
845#endif
846#ifdef CONFIG_ETHER_ON_FEC2
847 {
848 .compatible = "fsl,pq1-fec2",
849 .data = 1,
850 },
851#endif
852 { }
853};
854
855U_BOOT_DRIVER(fec) = {
856 .name = "fec",
857 .id = UCLASS_ETH,
858 .of_match = fec_ids,
859 .probe = fec_probe,
860 .ops = &fec_ops,
861 .priv_auto = sizeof(struct ether_fcc_info_s),
862 .plat_auto = sizeof(struct eth_pdata),
863};