]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
23e7578c PCM |
2 | /* |
3 | * (c) 2015 Purna Chandra Mandal <[email protected]> | |
4 | * | |
23e7578c | 5 | */ |
1eb69ae4 | 6 | #include <cpu_func.h> |
23e7578c PCM |
7 | #include <errno.h> |
8 | #include <dm.h> | |
f7ae49fc | 9 | #include <log.h> |
336d4615 | 10 | #include <malloc.h> |
23e7578c PCM |
11 | #include <net.h> |
12 | #include <miiphy.h> | |
13 | #include <console.h> | |
1045315d | 14 | #include <time.h> |
23e7578c | 15 | #include <wait_bit.h> |
401d1c4f | 16 | #include <asm/global_data.h> |
23e7578c | 17 | #include <asm/gpio.h> |
c05ed00a | 18 | #include <linux/delay.h> |
68a6aa85 | 19 | #include <linux/mii.h> |
23e7578c PCM |
20 | |
21 | #include "pic32_eth.h" | |
22 | ||
23 | #define MAX_RX_BUF_SIZE 1536 | |
24 | #define MAX_RX_DESCR PKTBUFSRX | |
25 | #define MAX_TX_DESCR 2 | |
26 | ||
27 | DECLARE_GLOBAL_DATA_PTR; | |
28 | ||
29 | struct pic32eth_dev { | |
30 | struct eth_dma_desc rxd_ring[MAX_RX_DESCR]; | |
31 | struct eth_dma_desc txd_ring[MAX_TX_DESCR]; | |
32 | u32 rxd_idx; /* index of RX desc to read */ | |
33 | /* regs */ | |
34 | struct pic32_ectl_regs *ectl_regs; | |
35 | struct pic32_emac_regs *emac_regs; | |
36 | /* Phy */ | |
37 | struct phy_device *phydev; | |
38 | phy_interface_t phyif; | |
39 | u32 phy_addr; | |
40 | struct gpio_desc rst_gpio; | |
41 | }; | |
42 | ||
43 | void __weak board_netphy_reset(void *dev) | |
44 | { | |
45 | struct pic32eth_dev *priv = dev; | |
46 | ||
47 | if (!dm_gpio_is_valid(&priv->rst_gpio)) | |
48 | return; | |
49 | ||
50 | /* phy reset */ | |
51 | dm_gpio_set_value(&priv->rst_gpio, 0); | |
52 | udelay(300); | |
53 | dm_gpio_set_value(&priv->rst_gpio, 1); | |
54 | udelay(300); | |
55 | } | |
56 | ||
57 | /* Initialize mii(MDIO) interface, discover which PHY is | |
58 | * attached to the device, and configure it properly. | |
59 | */ | |
60 | static int pic32_mii_init(struct pic32eth_dev *priv) | |
61 | { | |
62 | struct pic32_ectl_regs *ectl_p = priv->ectl_regs; | |
63 | struct pic32_emac_regs *emac_p = priv->emac_regs; | |
64 | ||
65 | /* board phy reset */ | |
66 | board_netphy_reset(priv); | |
67 | ||
68 | /* disable RX, TX & all transactions */ | |
69 | writel(ETHCON_ON | ETHCON_TXRTS | ETHCON_RXEN, &ectl_p->con1.clr); | |
70 | ||
71 | /* wait till busy */ | |
48263504 ÁFR |
72 | wait_for_bit_le32(&ectl_p->stat.raw, ETHSTAT_BUSY, false, |
73 | CONFIG_SYS_HZ, false); | |
23e7578c PCM |
74 | |
75 | /* turn controller ON to access PHY over MII */ | |
76 | writel(ETHCON_ON, &ectl_p->con1.set); | |
77 | ||
78 | mdelay(10); | |
79 | ||
80 | /* reset MAC */ | |
81 | writel(EMAC_SOFTRESET, &emac_p->cfg1.set); /* reset assert */ | |
82 | mdelay(10); | |
83 | writel(EMAC_SOFTRESET, &emac_p->cfg1.clr); /* reset deassert */ | |
84 | ||
85 | /* initialize MDIO/MII */ | |
86 | if (priv->phyif == PHY_INTERFACE_MODE_RMII) { | |
87 | writel(EMAC_RMII_RESET, &emac_p->supp.set); | |
88 | mdelay(10); | |
89 | writel(EMAC_RMII_RESET, &emac_p->supp.clr); | |
90 | } | |
91 | ||
92 | return pic32_mdio_init(PIC32_MDIO_NAME, (ulong)&emac_p->mii); | |
93 | } | |
94 | ||
95 | static int pic32_phy_init(struct pic32eth_dev *priv, struct udevice *dev) | |
96 | { | |
97 | struct mii_dev *mii; | |
98 | ||
99 | mii = miiphy_get_dev_by_name(PIC32_MDIO_NAME); | |
100 | ||
101 | /* find & connect PHY */ | |
102 | priv->phydev = phy_connect(mii, priv->phy_addr, | |
103 | dev, priv->phyif); | |
104 | if (!priv->phydev) { | |
105 | printf("%s: %s: Error, PHY connect\n", __FILE__, __func__); | |
106 | return 0; | |
107 | } | |
108 | ||
109 | /* Wait for phy to complete reset */ | |
110 | mdelay(10); | |
111 | ||
112 | /* configure supported modes */ | |
113 | priv->phydev->supported = SUPPORTED_10baseT_Half | | |
114 | SUPPORTED_10baseT_Full | | |
115 | SUPPORTED_100baseT_Half | | |
116 | SUPPORTED_100baseT_Full | | |
117 | SUPPORTED_Autoneg; | |
118 | ||
119 | priv->phydev->advertising = ADVERTISED_10baseT_Half | | |
120 | ADVERTISED_10baseT_Full | | |
121 | ADVERTISED_100baseT_Half | | |
122 | ADVERTISED_100baseT_Full | | |
123 | ADVERTISED_Autoneg; | |
124 | ||
125 | priv->phydev->autoneg = AUTONEG_ENABLE; | |
126 | ||
127 | return 0; | |
128 | } | |
129 | ||
130 | /* Configure MAC based on negotiated speed and duplex | |
131 | * reported by PHY. | |
132 | */ | |
133 | static int pic32_mac_adjust_link(struct pic32eth_dev *priv) | |
134 | { | |
135 | struct phy_device *phydev = priv->phydev; | |
136 | struct pic32_emac_regs *emac_p = priv->emac_regs; | |
137 | ||
138 | if (!phydev->link) { | |
139 | printf("%s: No link.\n", phydev->dev->name); | |
140 | return -EINVAL; | |
141 | } | |
142 | ||
143 | if (phydev->duplex) { | |
144 | writel(EMAC_FULLDUP, &emac_p->cfg2.set); | |
145 | writel(FULLDUP_GAP_TIME, &emac_p->ipgt.raw); | |
146 | } else { | |
147 | writel(EMAC_FULLDUP, &emac_p->cfg2.clr); | |
148 | writel(HALFDUP_GAP_TIME, &emac_p->ipgt.raw); | |
149 | } | |
150 | ||
151 | switch (phydev->speed) { | |
152 | case SPEED_100: | |
153 | writel(EMAC_RMII_SPD100, &emac_p->supp.set); | |
154 | break; | |
155 | case SPEED_10: | |
156 | writel(EMAC_RMII_SPD100, &emac_p->supp.clr); | |
157 | break; | |
158 | default: | |
159 | printf("%s: Speed was bad\n", phydev->dev->name); | |
160 | return -EINVAL; | |
161 | } | |
162 | ||
163 | printf("pic32eth: PHY is %s with %dbase%s, %s\n", | |
164 | phydev->drv->name, phydev->speed, | |
165 | (phydev->port == PORT_TP) ? "T" : "X", | |
166 | (phydev->duplex) ? "full" : "half"); | |
167 | ||
168 | return 0; | |
169 | } | |
170 | ||
171 | static void pic32_mac_init(struct pic32eth_dev *priv, u8 *macaddr) | |
172 | { | |
173 | struct pic32_emac_regs *emac_p = priv->emac_regs; | |
174 | u32 stat = 0, v; | |
175 | u64 expire; | |
176 | ||
177 | v = EMAC_TXPAUSE | EMAC_RXPAUSE | EMAC_RXENABLE; | |
178 | writel(v, &emac_p->cfg1.raw); | |
179 | ||
180 | v = EMAC_EXCESS | EMAC_AUTOPAD | EMAC_PADENABLE | | |
181 | EMAC_CRCENABLE | EMAC_LENGTHCK | EMAC_FULLDUP; | |
182 | writel(v, &emac_p->cfg2.raw); | |
183 | ||
184 | /* recommended back-to-back inter-packet gap for 10 Mbps half duplex */ | |
185 | writel(HALFDUP_GAP_TIME, &emac_p->ipgt.raw); | |
186 | ||
187 | /* recommended non-back-to-back interpacket gap is 0xc12 */ | |
188 | writel(0xc12, &emac_p->ipgr.raw); | |
189 | ||
190 | /* recommended collision window retry limit is 0x370F */ | |
191 | writel(0x370f, &emac_p->clrt.raw); | |
192 | ||
193 | /* set maximum frame length: allow VLAN tagged frame */ | |
194 | writel(0x600, &emac_p->maxf.raw); | |
195 | ||
196 | /* set the mac address */ | |
197 | writel(macaddr[0] | (macaddr[1] << 8), &emac_p->sa2.raw); | |
198 | writel(macaddr[2] | (macaddr[3] << 8), &emac_p->sa1.raw); | |
199 | writel(macaddr[4] | (macaddr[5] << 8), &emac_p->sa0.raw); | |
200 | ||
201 | /* default, enable 10 Mbps operation */ | |
202 | writel(EMAC_RMII_SPD100, &emac_p->supp.clr); | |
203 | ||
204 | /* wait until link status UP or deadline elapsed */ | |
205 | expire = get_ticks() + get_tbclk() * 2; | |
206 | for (; get_ticks() < expire;) { | |
207 | stat = phy_read(priv->phydev, priv->phy_addr, MII_BMSR); | |
208 | if (stat & BMSR_LSTATUS) | |
209 | break; | |
210 | } | |
211 | ||
212 | if (!(stat & BMSR_LSTATUS)) | |
213 | printf("MAC: Link is DOWN!\n"); | |
214 | ||
215 | /* delay to stabilize before any tx/rx */ | |
216 | mdelay(10); | |
217 | } | |
218 | ||
219 | static void pic32_mac_reset(struct pic32eth_dev *priv) | |
220 | { | |
221 | struct pic32_emac_regs *emac_p = priv->emac_regs; | |
222 | struct mii_dev *mii; | |
223 | ||
224 | /* Reset MAC */ | |
225 | writel(EMAC_SOFTRESET, &emac_p->cfg1.raw); | |
226 | mdelay(10); | |
227 | ||
228 | /* clear reset */ | |
229 | writel(0, &emac_p->cfg1.raw); | |
230 | ||
231 | /* Reset MII */ | |
232 | mii = priv->phydev->bus; | |
233 | if (mii && mii->reset) | |
234 | mii->reset(mii); | |
235 | } | |
236 | ||
237 | /* initializes the MAC and PHY, then establishes a link */ | |
238 | static void pic32_ctrl_reset(struct pic32eth_dev *priv) | |
239 | { | |
240 | struct pic32_ectl_regs *ectl_p = priv->ectl_regs; | |
241 | u32 v; | |
242 | ||
243 | /* disable RX, TX & any other transactions */ | |
244 | writel(ETHCON_ON | ETHCON_TXRTS | ETHCON_RXEN, &ectl_p->con1.clr); | |
245 | ||
246 | /* wait till busy */ | |
48263504 ÁFR |
247 | wait_for_bit_le32(&ectl_p->stat.raw, ETHSTAT_BUSY, false, |
248 | CONFIG_SYS_HZ, false); | |
23e7578c PCM |
249 | /* decrement received buffcnt to zero. */ |
250 | while (readl(&ectl_p->stat.raw) & ETHSTAT_BUFCNT) | |
251 | writel(ETHCON_BUFCDEC, &ectl_p->con1.set); | |
252 | ||
253 | /* clear any existing interrupt event */ | |
254 | writel(0xffffffff, &ectl_p->irq.clr); | |
255 | ||
256 | /* clear RX/TX start address */ | |
257 | writel(0xffffffff, &ectl_p->txst.clr); | |
258 | writel(0xffffffff, &ectl_p->rxst.clr); | |
259 | ||
260 | /* clear the receive filters */ | |
261 | writel(0x00ff, &ectl_p->rxfc.clr); | |
262 | ||
263 | /* set the receive filters | |
264 | * ETH_FILT_CRC_ERR_REJECT | |
265 | * ETH_FILT_RUNT_REJECT | |
266 | * ETH_FILT_UCAST_ACCEPT | |
267 | * ETH_FILT_MCAST_ACCEPT | |
268 | * ETH_FILT_BCAST_ACCEPT | |
269 | */ | |
270 | v = ETHRXFC_BCEN | ETHRXFC_MCEN | ETHRXFC_UCEN | | |
271 | ETHRXFC_RUNTEN | ETHRXFC_CRCOKEN; | |
272 | writel(v, &ectl_p->rxfc.set); | |
273 | ||
274 | /* turn controller ON to access PHY over MII */ | |
275 | writel(ETHCON_ON, &ectl_p->con1.set); | |
276 | } | |
277 | ||
278 | static void pic32_rx_desc_init(struct pic32eth_dev *priv) | |
279 | { | |
280 | struct pic32_ectl_regs *ectl_p = priv->ectl_regs; | |
281 | struct eth_dma_desc *rxd; | |
282 | u32 idx, bufsz; | |
283 | ||
284 | priv->rxd_idx = 0; | |
285 | for (idx = 0; idx < MAX_RX_DESCR; idx++) { | |
286 | rxd = &priv->rxd_ring[idx]; | |
287 | ||
288 | /* hw owned */ | |
289 | rxd->hdr = EDH_NPV | EDH_EOWN | EDH_STICKY; | |
290 | ||
291 | /* packet buffer address */ | |
292 | rxd->data_buff = virt_to_phys(net_rx_packets[idx]); | |
293 | ||
294 | /* link to next desc */ | |
295 | rxd->next_ed = virt_to_phys(rxd + 1); | |
296 | ||
297 | /* reset status */ | |
298 | rxd->stat1 = 0; | |
299 | rxd->stat2 = 0; | |
300 | ||
301 | /* decrement bufcnt */ | |
302 | writel(ETHCON_BUFCDEC, &ectl_p->con1.set); | |
303 | } | |
304 | ||
305 | /* link last descr to beginning of list */ | |
306 | rxd->next_ed = virt_to_phys(&priv->rxd_ring[0]); | |
307 | ||
308 | /* flush rx ring */ | |
309 | flush_dcache_range((ulong)priv->rxd_ring, | |
310 | (ulong)priv->rxd_ring + sizeof(priv->rxd_ring)); | |
311 | ||
312 | /* set rx desc-ring start address */ | |
313 | writel((ulong)virt_to_phys(&priv->rxd_ring[0]), &ectl_p->rxst.raw); | |
314 | ||
315 | /* RX Buffer size */ | |
316 | bufsz = readl(&ectl_p->con2.raw); | |
317 | bufsz &= ~(ETHCON_RXBUFSZ << ETHCON_RXBUFSZ_SHFT); | |
318 | bufsz |= ((MAX_RX_BUF_SIZE / 16) << ETHCON_RXBUFSZ_SHFT); | |
319 | writel(bufsz, &ectl_p->con2.raw); | |
320 | ||
321 | /* enable the receiver in hardware which allows hardware | |
322 | * to DMA received pkts to the descriptor pointer address. | |
323 | */ | |
324 | writel(ETHCON_RXEN, &ectl_p->con1.set); | |
325 | } | |
326 | ||
327 | static int pic32_eth_start(struct udevice *dev) | |
328 | { | |
c69cda25 | 329 | struct eth_pdata *pdata = dev_get_plat(dev); |
23e7578c PCM |
330 | struct pic32eth_dev *priv = dev_get_priv(dev); |
331 | ||
332 | /* controller */ | |
333 | pic32_ctrl_reset(priv); | |
334 | ||
335 | /* reset MAC */ | |
336 | pic32_mac_reset(priv); | |
337 | ||
338 | /* configure PHY */ | |
339 | phy_config(priv->phydev); | |
340 | ||
341 | /* initialize MAC */ | |
342 | pic32_mac_init(priv, &pdata->enetaddr[0]); | |
343 | ||
344 | /* init RX descriptor; TX descriptors are handled in xmit */ | |
345 | pic32_rx_desc_init(priv); | |
346 | ||
347 | /* Start up & update link status of PHY */ | |
348 | phy_startup(priv->phydev); | |
349 | ||
350 | /* adjust mac with phy link status */ | |
351 | return pic32_mac_adjust_link(priv); | |
352 | } | |
353 | ||
354 | static void pic32_eth_stop(struct udevice *dev) | |
355 | { | |
356 | struct pic32eth_dev *priv = dev_get_priv(dev); | |
357 | struct pic32_ectl_regs *ectl_p = priv->ectl_regs; | |
358 | struct pic32_emac_regs *emac_p = priv->emac_regs; | |
359 | ||
360 | /* Reset the phy if the controller is enabled */ | |
361 | if (readl(&ectl_p->con1.raw) & ETHCON_ON) | |
362 | phy_reset(priv->phydev); | |
363 | ||
364 | /* Shut down the PHY */ | |
365 | phy_shutdown(priv->phydev); | |
366 | ||
367 | /* Stop rx/tx */ | |
368 | writel(ETHCON_TXRTS | ETHCON_RXEN, &ectl_p->con1.clr); | |
369 | mdelay(10); | |
370 | ||
371 | /* reset MAC */ | |
372 | writel(EMAC_SOFTRESET, &emac_p->cfg1.raw); | |
373 | ||
374 | /* clear reset */ | |
375 | writel(0, &emac_p->cfg1.raw); | |
376 | mdelay(10); | |
377 | ||
378 | /* disable controller */ | |
379 | writel(ETHCON_ON, &ectl_p->con1.clr); | |
380 | mdelay(10); | |
381 | ||
382 | /* wait until everything is down */ | |
48263504 ÁFR |
383 | wait_for_bit_le32(&ectl_p->stat.raw, ETHSTAT_BUSY, false, |
384 | 2 * CONFIG_SYS_HZ, false); | |
23e7578c PCM |
385 | |
386 | /* clear any existing interrupt event */ | |
387 | writel(0xffffffff, &ectl_p->irq.clr); | |
388 | } | |
389 | ||
390 | static int pic32_eth_send(struct udevice *dev, void *packet, int length) | |
391 | { | |
392 | struct pic32eth_dev *priv = dev_get_priv(dev); | |
393 | struct pic32_ectl_regs *ectl_p = priv->ectl_regs; | |
394 | struct eth_dma_desc *txd; | |
395 | u64 deadline; | |
396 | ||
397 | txd = &priv->txd_ring[0]; | |
398 | ||
399 | /* set proper flags & length in descriptor header */ | |
400 | txd->hdr = EDH_SOP | EDH_EOP | EDH_EOWN | EDH_BCOUNT(length); | |
401 | ||
402 | /* pass buffer address to hardware */ | |
403 | txd->data_buff = virt_to_phys(packet); | |
404 | ||
405 | debug("%s: %d / .hdr %x, .data_buff %x, .stat %x, .nexted %x\n", | |
406 | __func__, __LINE__, txd->hdr, txd->data_buff, txd->stat2, | |
407 | txd->next_ed); | |
408 | ||
409 | /* cache flush (packet) */ | |
410 | flush_dcache_range((ulong)packet, (ulong)packet + length); | |
411 | ||
412 | /* cache flush (txd) */ | |
413 | flush_dcache_range((ulong)txd, (ulong)txd + sizeof(*txd)); | |
414 | ||
415 | /* pass descriptor table base to h/w */ | |
416 | writel(virt_to_phys(txd), &ectl_p->txst.raw); | |
417 | ||
418 | /* ready to send enabled, hardware can now send the packet(s) */ | |
419 | writel(ETHCON_TXRTS | ETHCON_ON, &ectl_p->con1.set); | |
420 | ||
421 | /* wait until tx has completed and h/w has released ownership | |
422 | * of the tx descriptor or timeout elapsed. | |
423 | */ | |
424 | deadline = get_ticks() + get_tbclk(); | |
425 | for (;;) { | |
426 | /* check timeout */ | |
427 | if (get_ticks() > deadline) | |
428 | return -ETIMEDOUT; | |
429 | ||
430 | if (ctrlc()) | |
431 | return -EINTR; | |
432 | ||
433 | /* tx completed ? */ | |
434 | if (readl(&ectl_p->con1.raw) & ETHCON_TXRTS) { | |
435 | udelay(1); | |
436 | continue; | |
437 | } | |
438 | ||
439 | /* h/w not released ownership yet? */ | |
440 | invalidate_dcache_range((ulong)txd, (ulong)txd + sizeof(*txd)); | |
441 | if (!(txd->hdr & EDH_EOWN)) | |
442 | break; | |
443 | } | |
444 | ||
445 | return 0; | |
446 | } | |
447 | ||
448 | static int pic32_eth_recv(struct udevice *dev, int flags, uchar **packetp) | |
449 | { | |
450 | struct pic32eth_dev *priv = dev_get_priv(dev); | |
451 | struct eth_dma_desc *rxd; | |
452 | u32 idx = priv->rxd_idx; | |
453 | u32 rx_count; | |
454 | ||
455 | /* find the next ready to receive */ | |
456 | rxd = &priv->rxd_ring[idx]; | |
457 | ||
458 | invalidate_dcache_range((ulong)rxd, (ulong)rxd + sizeof(*rxd)); | |
459 | /* check if owned by MAC */ | |
460 | if (rxd->hdr & EDH_EOWN) | |
461 | return -EAGAIN; | |
462 | ||
463 | /* Sanity check on header: SOP and EOP */ | |
464 | if ((rxd->hdr & (EDH_SOP | EDH_EOP)) != (EDH_SOP | EDH_EOP)) { | |
465 | printf("%s: %s, rx pkt across multiple descr\n", | |
466 | __FILE__, __func__); | |
467 | return 0; | |
468 | } | |
469 | ||
470 | debug("%s: %d /idx %i, hdr=%x, data_buff %x, stat %x, nexted %x\n", | |
471 | __func__, __LINE__, idx, rxd->hdr, | |
472 | rxd->data_buff, rxd->stat2, rxd->next_ed); | |
473 | ||
474 | /* Sanity check on rx_stat: OK, CRC */ | |
475 | if (!RSV_RX_OK(rxd->stat2) || RSV_CRC_ERR(rxd->stat2)) { | |
476 | debug("%s: %s: Error, rx problem detected\n", | |
477 | __FILE__, __func__); | |
478 | return 0; | |
479 | } | |
480 | ||
481 | /* invalidate dcache */ | |
482 | rx_count = RSV_RX_COUNT(rxd->stat2); | |
483 | invalidate_dcache_range((ulong)net_rx_packets[idx], | |
484 | (ulong)net_rx_packets[idx] + rx_count); | |
485 | ||
486 | /* Pass the packet to protocol layer */ | |
487 | *packetp = net_rx_packets[idx]; | |
488 | ||
489 | /* increment number of bytes rcvd (ignore CRC) */ | |
490 | return rx_count - 4; | |
491 | } | |
492 | ||
493 | static int pic32_eth_free_pkt(struct udevice *dev, uchar *packet, int length) | |
494 | { | |
495 | struct pic32eth_dev *priv = dev_get_priv(dev); | |
496 | struct pic32_ectl_regs *ectl_p = priv->ectl_regs; | |
497 | struct eth_dma_desc *rxd; | |
498 | int idx = priv->rxd_idx; | |
499 | ||
500 | /* sanity check */ | |
501 | if (packet != net_rx_packets[idx]) { | |
502 | printf("rxd_id %d: packet is not matched,\n", idx); | |
503 | return -EAGAIN; | |
504 | } | |
505 | ||
506 | /* prepare for receive */ | |
507 | rxd = &priv->rxd_ring[idx]; | |
508 | rxd->hdr = EDH_STICKY | EDH_NPV | EDH_EOWN; | |
509 | ||
510 | flush_dcache_range((ulong)rxd, (ulong)rxd + sizeof(*rxd)); | |
511 | ||
512 | /* decrement rx pkt count */ | |
513 | writel(ETHCON_BUFCDEC, &ectl_p->con1.set); | |
514 | ||
515 | debug("%s: %d / idx %i, hdr %x, data_buff %x, stat %x, nexted %x\n", | |
516 | __func__, __LINE__, idx, rxd->hdr, rxd->data_buff, | |
517 | rxd->stat2, rxd->next_ed); | |
518 | ||
519 | priv->rxd_idx = (priv->rxd_idx + 1) % MAX_RX_DESCR; | |
520 | ||
521 | return 0; | |
522 | } | |
523 | ||
524 | static const struct eth_ops pic32_eth_ops = { | |
525 | .start = pic32_eth_start, | |
526 | .send = pic32_eth_send, | |
527 | .recv = pic32_eth_recv, | |
528 | .free_pkt = pic32_eth_free_pkt, | |
529 | .stop = pic32_eth_stop, | |
530 | }; | |
531 | ||
532 | static int pic32_eth_probe(struct udevice *dev) | |
533 | { | |
c69cda25 | 534 | struct eth_pdata *pdata = dev_get_plat(dev); |
23e7578c | 535 | struct pic32eth_dev *priv = dev_get_priv(dev); |
23e7578c PCM |
536 | void __iomem *iobase; |
537 | fdt_addr_t addr; | |
538 | fdt_size_t size; | |
539 | int offset = 0; | |
540 | int phy_addr = -1; | |
541 | ||
e160f7d4 SG |
542 | addr = fdtdec_get_addr_size(gd->fdt_blob, dev_of_offset(dev), "reg", |
543 | &size); | |
23e7578c PCM |
544 | if (addr == FDT_ADDR_T_NONE) |
545 | return -EINVAL; | |
546 | ||
547 | iobase = ioremap(addr, size); | |
548 | pdata->iobase = (phys_addr_t)addr; | |
549 | ||
550 | /* get phy mode */ | |
123ca114 | 551 | pdata->phy_interface = dev_read_phy_mode(dev); |
ffb0f6f4 | 552 | if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) |
23e7578c | 553 | return -EINVAL; |
23e7578c PCM |
554 | |
555 | /* get phy addr */ | |
e160f7d4 | 556 | offset = fdtdec_lookup_phandle(gd->fdt_blob, dev_of_offset(dev), |
23e7578c PCM |
557 | "phy-handle"); |
558 | if (offset > 0) | |
559 | phy_addr = fdtdec_get_int(gd->fdt_blob, offset, "reg", -1); | |
560 | ||
561 | /* phy reset gpio */ | |
150c5afe | 562 | gpio_request_by_name_nodev(dev_ofnode(dev), "reset-gpios", 0, |
23e7578c PCM |
563 | &priv->rst_gpio, GPIOD_IS_OUT); |
564 | ||
565 | priv->phyif = pdata->phy_interface; | |
566 | priv->phy_addr = phy_addr; | |
567 | priv->ectl_regs = iobase; | |
568 | priv->emac_regs = iobase + PIC32_EMAC1CFG1; | |
569 | ||
570 | pic32_mii_init(priv); | |
571 | ||
572 | return pic32_phy_init(priv, dev); | |
573 | } | |
574 | ||
575 | static int pic32_eth_remove(struct udevice *dev) | |
576 | { | |
577 | struct pic32eth_dev *priv = dev_get_priv(dev); | |
578 | struct mii_dev *bus; | |
579 | ||
580 | dm_gpio_free(dev, &priv->rst_gpio); | |
581 | phy_shutdown(priv->phydev); | |
582 | free(priv->phydev); | |
583 | bus = miiphy_get_dev_by_name(PIC32_MDIO_NAME); | |
584 | mdio_unregister(bus); | |
585 | mdio_free(bus); | |
586 | iounmap(priv->ectl_regs); | |
587 | return 0; | |
588 | } | |
589 | ||
590 | static const struct udevice_id pic32_eth_ids[] = { | |
591 | { .compatible = "microchip,pic32mzda-eth" }, | |
592 | { } | |
593 | }; | |
594 | ||
595 | U_BOOT_DRIVER(pic32_ethernet) = { | |
596 | .name = "pic32_ethernet", | |
597 | .id = UCLASS_ETH, | |
598 | .of_match = pic32_eth_ids, | |
599 | .probe = pic32_eth_probe, | |
600 | .remove = pic32_eth_remove, | |
601 | .ops = &pic32_eth_ops, | |
41575d8e | 602 | .priv_auto = sizeof(struct pic32eth_dev), |
caa4daa2 | 603 | .plat_auto = sizeof(struct eth_pdata), |
23e7578c | 604 | }; |