1 /* Blackfin Ethernet Media Access Controller (EMAC) model.
3 Copyright (C) 2010-2024 Free Software Foundation, Inc.
4 Contributed by Analog Devices, Inc.
6 This file is part of simulators.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 /* This must come before any other includes. */
28 #ifdef HAVE_SYS_IOCTL_H
29 #include <sys/ioctl.h>
34 #ifdef HAVE_LINUX_IF_TUN_H
35 #include <linux/if_tun.h>
38 #ifdef HAVE_LINUX_IF_TUN_H
47 #include "dv-bfin_emac.h"
49 /* XXX: This doesn't support partial DMA transfers. */
50 /* XXX: The TUN pieces should be pushed to the PHY so that we work with
51 multiple "networks" and the PHY takes care of it. */
55 /* This top portion matches common dv_bfin struct. */
57 struct hw
*dma_master
;
66 /* Order after here is important -- matches hardware MMR layout. */
67 bu32 opmode
, addrlo
, addrhi
, hashlo
, hashhi
, staadd
, stadat
, flc
, vlan1
, vlan2
;
69 bu32 wkup_ctl
, wkup_ffmsk0
, wkup_ffmsk1
, wkup_ffmsk2
, wkup_ffmsk3
;
70 bu32 wkup_ffcmd
, wkup_ffoff
, wkup_ffcrc0
, wkup_ffcrc1
;
72 bu32 sysctl
, systat
, rx_stat
, rx_stky
, rx_irqe
, tx_stat
, tx_stky
, tx_irqe
;
73 bu32 mmc_ctl
, mmc_rirqs
, mmc_rirqe
, mmc_tirqs
, mmc_tirqe
;
75 bu16
BFIN_MMR_16(ptp_ctl
);
76 bu16
BFIN_MMR_16(ptp_ie
);
77 bu16
BFIN_MMR_16(ptp_istat
);
78 bu32 ptp_foff
, ptp_fv1
, ptp_fv2
, ptp_fv3
, ptp_addend
, ptp_accr
, ptp_offset
;
79 bu32 ptp_timelo
, ptp_timehi
, ptp_rxsnaplo
, ptp_rxsnaphi
, ptp_txsnaplo
;
80 bu32 ptp_txsnaphi
, ptp_alarmlo
, ptp_alarmhi
, ptp_id_off
, ptp_id_snap
;
81 bu32 ptp_pps_startlo
, ptp_pps_starthi
, ptp_pps_period
;
83 bu32 rxc_ok
, rxc_fcs
, rxc_lign
, rxc_octet
, rxc_dmaovf
, rxc_unicst
, rxc_multi
;
84 bu32 rxc_broad
, rxc_lnerri
, rxc_lnerro
, rxc_long
, rxc_macctl
, rxc_opcode
;
85 bu32 rxc_pause
, rxc_allfrm
, rxc_alloct
, rxc_typed
, rxc_short
, rxc_eq64
;
86 bu32 rxc_lt128
, rxc_lt256
, rxc_lt512
, rxc_lt1024
, rxc_ge1024
;
88 bu32 txc_ok
, txc_1col
, txc_gt1col
, txc_octet
, txc_defer
, txc_latecl
;
89 bu32 txc_xs_col
, txc_dmaund
, txc_crserr
, txc_unicst
, txc_multi
, txc_broad
;
90 bu32 txc_xs_dfr
, txc_macctl
, txc_allfrm
, txc_alloct
, txc_eq64
, txc_lt128
;
91 bu32 txc_lt256
, txc_lt512
, txc_lt1024
, txc_ge1024
, txc_abort
;
93 #define mmr_base() offsetof(struct bfin_emac, opmode)
94 #define mmr_offset(mmr) (offsetof(struct bfin_emac, mmr) - mmr_base())
95 #define mmr_idx(mmr) (mmr_offset (mmr) / 4)
97 static const char * const mmr_names
[BFIN_MMR_EMAC_SIZE
/ 4] =
99 "EMAC_OPMODE", "EMAC_ADDRLO", "EMAC_ADDRHI", "EMAC_HASHLO", "EMAC_HASHHI",
100 "EMAC_STAADD", "EMAC_STADAT", "EMAC_FLC", "EMAC_VLAN1", "EMAC_VLAN2", NULL
,
101 "EMAC_WKUP_CTL", "EMAC_WKUP_FFMSK0", "EMAC_WKUP_FFMSK1", "EMAC_WKUP_FFMSK2",
102 "EMAC_WKUP_FFMSK3", "EMAC_WKUP_FFCMD", "EMAC_WKUP_FFOFF", "EMAC_WKUP_FFCRC0",
103 "EMAC_WKUP_FFCRC1", [mmr_idx (sysctl
)] = "EMAC_SYSCTL", "EMAC_SYSTAT",
104 "EMAC_RX_STAT", "EMAC_RX_STKY", "EMAC_RX_IRQE", "EMAC_TX_STAT",
105 "EMAC_TX_STKY", "EMAC_TX_IRQE", "EMAC_MMC_CTL", "EMAC_MMC_RIRQS",
106 "EMAC_MMC_RIRQE", "EMAC_MMC_TIRQS", "EMAC_MMC_TIRQE",
107 [mmr_idx (ptp_ctl
)] = "EMAC_PTP_CTL", "EMAC_PTP_IE", "EMAC_PTP_ISTAT",
108 "EMAC_PTP_FOFF", "EMAC_PTP_FV1", "EMAC_PTP_FV2", "EMAC_PTP_FV3",
109 "EMAC_PTP_ADDEND", "EMAC_PTP_ACCR", "EMAC_PTP_OFFSET", "EMAC_PTP_TIMELO",
110 "EMAC_PTP_TIMEHI", "EMAC_PTP_RXSNAPLO", "EMAC_PTP_RXSNAPHI",
111 "EMAC_PTP_TXSNAPLO", "EMAC_PTP_TXSNAPHI", "EMAC_PTP_ALARMLO",
112 "EMAC_PTP_ALARMHI", "EMAC_PTP_ID_OFF", "EMAC_PTP_ID_SNAP",
113 "EMAC_PTP_PPS_STARTLO", "EMAC_PTP_PPS_STARTHI", "EMAC_PTP_PPS_PERIOD",
114 [mmr_idx (rxc_ok
)] = "EMAC_RXC_OK", "EMAC_RXC_FCS", "EMAC_RXC_LIGN",
115 "EMAC_RXC_OCTET", "EMAC_RXC_DMAOVF", "EMAC_RXC_UNICST", "EMAC_RXC_MULTI",
116 "EMAC_RXC_BROAD", "EMAC_RXC_LNERRI", "EMAC_RXC_LNERRO", "EMAC_RXC_LONG",
117 "EMAC_RXC_MACCTL", "EMAC_RXC_OPCODE", "EMAC_RXC_PAUSE", "EMAC_RXC_ALLFRM",
118 "EMAC_RXC_ALLOCT", "EMAC_RXC_TYPED", "EMAC_RXC_SHORT", "EMAC_RXC_EQ64",
119 "EMAC_RXC_LT128", "EMAC_RXC_LT256", "EMAC_RXC_LT512", "EMAC_RXC_LT1024",
121 [mmr_idx (txc_ok
)] = "EMAC_TXC_OK", "EMAC_TXC_1COL", "EMAC_TXC_GT1COL",
122 "EMAC_TXC_OCTET", "EMAC_TXC_DEFER", "EMAC_TXC_LATECL", "EMAC_TXC_XS_COL",
123 "EMAC_TXC_DMAUND", "EMAC_TXC_CRSERR", "EMAC_TXC_UNICST", "EMAC_TXC_MULTI",
124 "EMAC_TXC_BROAD", "EMAC_TXC_XS_DFR", "EMAC_TXC_MACCTL", "EMAC_TXC_ALLFRM",
125 "EMAC_TXC_ALLOCT", "EMAC_TXC_EQ64", "EMAC_TXC_LT128", "EMAC_TXC_LT256",
126 "EMAC_TXC_LT512", "EMAC_TXC_LT1024", "EMAC_TXC_GE1024", "EMAC_TXC_ABORT",
128 #define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
131 mii_find_phy (struct hw
*me
, bu8 addr
)
133 struct hw
*phy
= hw_child (me
);
134 while (phy
&& --addr
)
135 phy
= hw_sibling (phy
);
140 mii_write (struct hw
*me
)
142 SIM_DESC sd
= hw_system (me
);
143 struct bfin_emac
*emac
= hw_data (me
);
145 bu8 addr
= PHYAD (emac
->staadd
);
146 bu8 reg
= REGAD (emac
->staadd
);
147 bu16 data
= emac
->stadat
;
149 phy
= mii_find_phy (me
, addr
);
152 sim_hw_io_write_buffer (sd
, phy
, &data
, 1, reg
, 2);
156 mii_read (struct hw
*me
)
158 SIM_DESC sd
= hw_system (me
);
159 struct bfin_emac
*emac
= hw_data (me
);
161 bu8 addr
= PHYAD (emac
->staadd
);
162 bu8 reg
= REGAD (emac
->staadd
);
165 phy
= mii_find_phy (me
, addr
);
166 if (!phy
|| sim_hw_io_read_buffer (sd
, phy
, &data
, 1, reg
, 2) != 2)
173 bfin_emac_io_write_buffer (struct hw
*me
, const void *source
,
174 int space
, address_word addr
, unsigned nr_bytes
)
176 struct bfin_emac
*emac
= hw_data (me
);
181 /* Invalid access mode is higher priority than missing register. */
182 /* XXX: 16bit accesses are allowed ... */
183 if (!dv_bfin_mmr_require_32 (me
, addr
, nr_bytes
, true))
185 value
= dv_load_4 (source
);
187 mmr_off
= addr
- emac
->base
;
188 valuep
= (void *)((uintptr_t)emac
+ mmr_base() + mmr_off
);
194 case mmr_offset(hashlo
):
195 case mmr_offset(hashhi
):
196 case mmr_offset(stadat
):
197 case mmr_offset(flc
):
198 case mmr_offset(vlan1
):
199 case mmr_offset(vlan2
):
200 case mmr_offset(wkup_ffmsk0
):
201 case mmr_offset(wkup_ffmsk1
):
202 case mmr_offset(wkup_ffmsk2
):
203 case mmr_offset(wkup_ffmsk3
):
204 case mmr_offset(wkup_ffcmd
):
205 case mmr_offset(wkup_ffoff
):
206 case mmr_offset(wkup_ffcrc0
):
207 case mmr_offset(wkup_ffcrc1
):
208 case mmr_offset(sysctl
):
209 case mmr_offset(rx_irqe
):
210 case mmr_offset(tx_irqe
):
211 case mmr_offset(mmc_rirqe
):
212 case mmr_offset(mmc_tirqe
):
215 case mmr_offset(opmode
):
216 if (!(*valuep
& RE
) && (value
& RE
))
217 emac
->rx_stat
&= ~RX_COMP
;
218 if (!(*valuep
& TE
) && (value
& TE
))
219 emac
->tx_stat
&= ~TX_COMP
;
222 case mmr_offset(addrlo
):
223 case mmr_offset(addrhi
):
226 case mmr_offset(wkup_ctl
):
227 dv_w1c_4_partial (valuep
, value
, 0xf20);
229 case mmr_offset(systat
):
230 dv_w1c_4 (valuep
, value
, 0xe1);
232 case mmr_offset(staadd
):
233 *valuep
= value
| STABUSY
;
240 case mmr_offset(rx_stat
):
241 case mmr_offset(tx_stat
):
242 /* Discard writes to these. */
244 case mmr_offset(rx_stky
):
245 case mmr_offset(tx_stky
):
246 case mmr_offset(mmc_rirqs
):
247 case mmr_offset(mmc_tirqs
):
248 dv_w1c_4 (valuep
, value
, -1);
250 case mmr_offset(mmc_ctl
):
251 /* Writing to bit 0 clears all counters. */
252 *valuep
= value
& ~1;
255 memset (&emac
->rxc_ok
, 0, mmr_offset (rxc_ge1024
) - mmr_offset (rxc_ok
) + 4);
256 memset (&emac
->txc_ok
, 0, mmr_offset (txc_abort
) - mmr_offset (txc_ok
) + 4);
259 case mmr_offset(rxc_ok
) ... mmr_offset(rxc_ge1024
):
260 case mmr_offset(txc_ok
) ... mmr_offset(txc_abort
):
261 /* XXX: Are these supposed to be read-only ? */
264 case mmr_offset(ptp_ctl
) ... mmr_offset(ptp_pps_period
):
265 /* XXX: Only on some models; ignore for now. */
268 dv_bfin_mmr_invalid (me
, addr
, nr_bytes
, true);
276 bfin_emac_io_read_buffer (struct hw
*me
, void *dest
,
277 int space
, address_word addr
, unsigned nr_bytes
)
279 struct bfin_emac
*emac
= hw_data (me
);
283 /* Invalid access mode is higher priority than missing register. */
284 /* XXX: 16bit accesses are allowed ... */
285 if (!dv_bfin_mmr_require_32 (me
, addr
, nr_bytes
, false))
288 mmr_off
= addr
- emac
->base
;
289 valuep
= (void *)((uintptr_t)emac
+ mmr_base() + mmr_off
);
295 case mmr_offset(opmode
):
296 case mmr_offset(addrlo
):
297 case mmr_offset(addrhi
):
298 case mmr_offset(hashlo
):
299 case mmr_offset(hashhi
):
300 case mmr_offset(staadd
):
301 case mmr_offset(stadat
):
302 case mmr_offset(flc
):
303 case mmr_offset(vlan1
):
304 case mmr_offset(vlan2
):
305 case mmr_offset(wkup_ctl
):
306 case mmr_offset(wkup_ffmsk0
):
307 case mmr_offset(wkup_ffmsk1
):
308 case mmr_offset(wkup_ffmsk2
):
309 case mmr_offset(wkup_ffmsk3
):
310 case mmr_offset(wkup_ffcmd
):
311 case mmr_offset(wkup_ffoff
):
312 case mmr_offset(wkup_ffcrc0
):
313 case mmr_offset(wkup_ffcrc1
):
314 case mmr_offset(sysctl
):
315 case mmr_offset(systat
):
316 case mmr_offset(rx_stat
):
317 case mmr_offset(rx_stky
):
318 case mmr_offset(rx_irqe
):
319 case mmr_offset(tx_stat
):
320 case mmr_offset(tx_stky
):
321 case mmr_offset(tx_irqe
):
322 case mmr_offset(mmc_rirqs
):
323 case mmr_offset(mmc_rirqe
):
324 case mmr_offset(mmc_tirqs
):
325 case mmr_offset(mmc_tirqe
):
326 case mmr_offset(mmc_ctl
):
327 case mmr_offset(rxc_ok
) ... mmr_offset(rxc_ge1024
):
328 case mmr_offset(txc_ok
) ... mmr_offset(txc_abort
):
329 dv_store_4 (dest
, *valuep
);
331 case mmr_offset(ptp_ctl
) ... mmr_offset(ptp_pps_period
):
332 /* XXX: Only on some models; ignore for now. */
335 dv_bfin_mmr_invalid (me
, addr
, nr_bytes
, false);
343 attach_bfin_emac_regs (struct hw
*me
, struct bfin_emac
*emac
)
345 address_word attach_address
;
347 unsigned attach_size
;
348 reg_property_spec reg
;
350 if (hw_find_property (me
, "reg") == NULL
)
351 hw_abort (me
, "Missing \"reg\" property");
353 if (!hw_find_reg_array_property (me
, "reg", 0, ®
))
354 hw_abort (me
, "\"reg\" property must contain three addr/size entries");
356 hw_unit_address_to_attach_address (hw_parent (me
),
358 &attach_space
, &attach_address
, me
);
359 hw_unit_size_to_attach_size (hw_parent (me
), ®
.size
, &attach_size
, me
);
361 if (attach_size
!= BFIN_MMR_EMAC_SIZE
)
362 hw_abort (me
, "\"reg\" size must be %#x", BFIN_MMR_EMAC_SIZE
);
364 hw_attach_address (hw_parent (me
),
365 0, attach_space
, attach_address
, attach_size
, me
);
367 emac
->base
= attach_address
;
370 static struct dv_bfin
*dma_tx
;
373 bfin_emac_dma_read_buffer (struct hw
*me
, void *dest
, int space
,
374 unsigned_word addr
, unsigned nr_bytes
)
376 struct bfin_emac
*emac
= hw_data (me
);
377 struct dv_bfin
*dma
= hw_data (emac
->dma_master
);
378 unsigned char *data
= dest
;
379 static bool flop
; /* XXX: This sucks. */
383 HW_TRACE_DMA_READ ();
387 /* Handle the TX turn around and write the status. */
388 emac
->tx_stat
|= TX_OK
;
389 emac
->tx_stky
|= TX_OK
;
391 memcpy (data
, &emac
->tx_stat
, 4);
397 if (!(emac
->opmode
& RE
))
403 /* Outgoing DMA buffer has 16bit len prepended to it. */
406 /* This doesn't seem to work.
407 if (emac->sysctl & RXDWA)
413 ret
= read (emac
->tap
, data
, nr_bytes
);
416 ret
+= 4; /* include crc */
417 pad_ret
= max (ret
+ 4, 64);
419 memcpy (dest
, &len
, 2);
421 pad_ret
= (pad_ret
+ 3) & ~3;
423 memset (data
+ ret
, 0, pad_ret
- ret
);
426 /* XXX: Need to check -- u-boot doesn't look at this. */
427 if (emac
->sysctl
& RXCKS
)
434 /* XXX: Don't support promiscuous yet. */
435 emac
->rx_stat
|= RX_ACCEPT
;
436 emac
->rx_stat
= (emac
->rx_stat
& ~RX_FRLEN
) | len
;
438 emac
->rx_stat
|= RX_COMP
;
439 emac
->rx_stky
|= RX_COMP
;
443 /* Write the RX status and crc info. */
444 emac
->rx_stat
|= RX_OK
;
445 emac
->rx_stky
|= RX_OK
;
448 if (emac
->sysctl
& RXCKS
)
450 memcpy (data
, &emac
->rx_crc
, 4);
454 memcpy (data
, &emac
->rx_stat
, 4);
463 bfin_emac_dma_write_buffer (struct hw
*me
, const void *source
,
464 int space
, unsigned_word addr
,
466 int violate_read_only_section
)
468 struct bfin_emac
*emac
= hw_data (me
);
469 struct dv_bfin
*dma
= hw_data (emac
->dma_master
);
470 const unsigned char *data
= source
;
474 HW_TRACE_DMA_WRITE ();
476 if (!(emac
->opmode
& TE
))
479 /* Incoming DMA buffer has 16bit len prepended to it. */
480 memcpy (&len
, data
, 2);
484 ret
= write (emac
->tap
, data
+ 2, len
);
489 emac
->tx_stat
|= TX_COMP
;
490 emac
->tx_stky
|= TX_COMP
;
497 static const struct hw_port_descriptor bfin_emac_ports
[] =
499 { "tx", DV_PORT_TX
, 0, output_port
, },
500 { "rx", DV_PORT_RX
, 0, output_port
, },
501 { "stat", DV_PORT_STAT
, 0, output_port
, },
506 bfin_emac_attach_address_callback (struct hw
*me
,
510 address_word nr_bytes
,
513 const hw_unit
*unit
= hw_unit_address (client
);
514 HW_TRACE ((me
, "attach - level=%d, space=%d, addr=0x%lx, nr_bytes=%lu, client=%s",
515 level
, space
, (unsigned long) addr
, (unsigned long) nr_bytes
, hw_path (client
)));
516 /* NOTE: At preset the space is assumed to be zero. Perhaphs the
517 space should be mapped onto something for instance: space0 -
518 unified memory; space1 - IO memory; ... */
519 sim_core_attach (hw_system (me
),
521 level
+ 10 + unit
->cells
[unit
->nr_cells
- 1],
522 access_read_write_exec
,
531 bfin_emac_delete (struct hw
*me
)
533 struct bfin_emac
*emac
= hw_data (me
);
538 bfin_emac_tap_init (struct hw
*me
)
541 struct bfin_emac
*emac
= hw_data (me
);
544 emac
->tap
= open ("/dev/net/tun", O_RDWR
);
547 HW_TRACE ((me
, "unable to open /dev/net/tun: %s", strerror (errno
)));
551 memset (&emac
->ifr
, 0, sizeof (emac
->ifr
));
552 emac
->ifr
.ifr_flags
= IFF_TAP
| IFF_NO_PI
;
553 strcpy (emac
->ifr
.ifr_name
, "tap-gdb");
555 flags
= 1 * 1024 * 1024;
556 if (ioctl (emac
->tap
, TUNSETIFF
, &emac
->ifr
) < 0
558 || ioctl (emac
->tap
, TUNSETNOCSUM
) < 0
561 || ioctl (emac
->tap
, TUNSETSNDBUF
, &flags
) < 0
565 HW_TRACE ((me
, "tap ioctl setup failed: %s", strerror (errno
)));
570 flags
= fcntl (emac
->tap
, F_GETFL
);
571 fcntl (emac
->tap
, F_SETFL
, flags
| O_NONBLOCK
);
576 bfin_emac_finish (struct hw
*me
)
578 struct bfin_emac
*emac
;
580 emac
= HW_ZALLOC (me
, struct bfin_emac
);
582 set_hw_data (me
, emac
);
583 set_hw_io_read_buffer (me
, bfin_emac_io_read_buffer
);
584 set_hw_io_write_buffer (me
, bfin_emac_io_write_buffer
);
585 set_hw_dma_read_buffer (me
, bfin_emac_dma_read_buffer
);
586 set_hw_dma_write_buffer (me
, bfin_emac_dma_write_buffer
);
587 set_hw_ports (me
, bfin_emac_ports
);
588 set_hw_attach_address (me
, bfin_emac_attach_address_callback
);
589 set_hw_delete (me
, bfin_emac_delete
);
591 attach_bfin_emac_regs (me
, emac
);
593 /* Initialize the EMAC. */
594 emac
->addrlo
= 0xffffffff;
595 emac
->addrhi
= 0x0000ffff;
596 emac
->vlan1
= 0x0000ffff;
597 emac
->vlan2
= 0x0000ffff;
598 emac
->sysctl
= 0x00003f00;
599 emac
->mmc_ctl
= 0x0000000a;
601 bfin_emac_tap_init (me
);
604 const struct hw_descriptor dv_bfin_emac_descriptor
[] =
606 {"bfin_emac", bfin_emac_finish
,},