1 /* Blackfin Ethernet Media Access Controller (EMAC) model.
3 Copyright (C) 2010-2020 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/>. */
27 #ifdef HAVE_SYS_IOCTL_H
28 #include <sys/ioctl.h>
33 #ifdef HAVE_LINUX_IF_TUN_H
34 #include <linux/if_tun.h>
37 #ifdef HAVE_LINUX_IF_TUN_H
46 #include "dv-bfin_emac.h"
48 /* XXX: This doesn't support partial DMA transfers. */
49 /* XXX: The TUN pieces should be pushed to the PHY so that we work with
50 multiple "networks" and the PHY takes care of it. */
54 /* This top portion matches common dv_bfin struct. */
56 struct hw
*dma_master
;
65 /* Order after here is important -- matches hardware MMR layout. */
66 bu32 opmode
, addrlo
, addrhi
, hashlo
, hashhi
, staadd
, stadat
, flc
, vlan1
, vlan2
;
68 bu32 wkup_ctl
, wkup_ffmsk0
, wkup_ffmsk1
, wkup_ffmsk2
, wkup_ffmsk3
;
69 bu32 wkup_ffcmd
, wkup_ffoff
, wkup_ffcrc0
, wkup_ffcrc1
;
71 bu32 sysctl
, systat
, rx_stat
, rx_stky
, rx_irqe
, tx_stat
, tx_stky
, tx_irqe
;
72 bu32 mmc_ctl
, mmc_rirqs
, mmc_rirqe
, mmc_tirqs
, mmc_tirqe
;
74 bu16
BFIN_MMR_16(ptp_ctl
);
75 bu16
BFIN_MMR_16(ptp_ie
);
76 bu16
BFIN_MMR_16(ptp_istat
);
77 bu32 ptp_foff
, ptp_fv1
, ptp_fv2
, ptp_fv3
, ptp_addend
, ptp_accr
, ptp_offset
;
78 bu32 ptp_timelo
, ptp_timehi
, ptp_rxsnaplo
, ptp_rxsnaphi
, ptp_txsnaplo
;
79 bu32 ptp_txsnaphi
, ptp_alarmlo
, ptp_alarmhi
, ptp_id_off
, ptp_id_snap
;
80 bu32 ptp_pps_startlo
, ptp_pps_starthi
, ptp_pps_period
;
82 bu32 rxc_ok
, rxc_fcs
, rxc_lign
, rxc_octet
, rxc_dmaovf
, rxc_unicst
, rxc_multi
;
83 bu32 rxc_broad
, rxc_lnerri
, rxc_lnerro
, rxc_long
, rxc_macctl
, rxc_opcode
;
84 bu32 rxc_pause
, rxc_allfrm
, rxc_alloct
, rxc_typed
, rxc_short
, rxc_eq64
;
85 bu32 rxc_lt128
, rxc_lt256
, rxc_lt512
, rxc_lt1024
, rxc_ge1024
;
87 bu32 txc_ok
, txc_1col
, txc_gt1col
, txc_octet
, txc_defer
, txc_latecl
;
88 bu32 txc_xs_col
, txc_dmaund
, txc_crserr
, txc_unicst
, txc_multi
, txc_broad
;
89 bu32 txc_xs_dfr
, txc_macctl
, txc_allfrm
, txc_alloct
, txc_eq64
, txc_lt128
;
90 bu32 txc_lt256
, txc_lt512
, txc_lt1024
, txc_ge1024
, txc_abort
;
92 #define mmr_base() offsetof(struct bfin_emac, opmode)
93 #define mmr_offset(mmr) (offsetof(struct bfin_emac, mmr) - mmr_base())
94 #define mmr_idx(mmr) (mmr_offset (mmr) / 4)
96 static const char * const mmr_names
[BFIN_MMR_EMAC_SIZE
/ 4] =
98 "EMAC_OPMODE", "EMAC_ADDRLO", "EMAC_ADDRHI", "EMAC_HASHLO", "EMAC_HASHHI",
99 "EMAC_STAADD", "EMAC_STADAT", "EMAC_FLC", "EMAC_VLAN1", "EMAC_VLAN2", NULL
,
100 "EMAC_WKUP_CTL", "EMAC_WKUP_FFMSK0", "EMAC_WKUP_FFMSK1", "EMAC_WKUP_FFMSK2",
101 "EMAC_WKUP_FFMSK3", "EMAC_WKUP_FFCMD", "EMAC_WKUP_FFOFF", "EMAC_WKUP_FFCRC0",
102 "EMAC_WKUP_FFCRC1", [mmr_idx (sysctl
)] = "EMAC_SYSCTL", "EMAC_SYSTAT",
103 "EMAC_RX_STAT", "EMAC_RX_STKY", "EMAC_RX_IRQE", "EMAC_TX_STAT",
104 "EMAC_TX_STKY", "EMAC_TX_IRQE", "EMAC_MMC_CTL", "EMAC_MMC_RIRQS",
105 "EMAC_MMC_RIRQE", "EMAC_MMC_TIRQS", "EMAC_MMC_TIRQE",
106 [mmr_idx (ptp_ctl
)] = "EMAC_PTP_CTL", "EMAC_PTP_IE", "EMAC_PTP_ISTAT",
107 "EMAC_PTP_FOFF", "EMAC_PTP_FV1", "EMAC_PTP_FV2", "EMAC_PTP_FV3",
108 "EMAC_PTP_ADDEND", "EMAC_PTP_ACCR", "EMAC_PTP_OFFSET", "EMAC_PTP_TIMELO",
109 "EMAC_PTP_TIMEHI", "EMAC_PTP_RXSNAPLO", "EMAC_PTP_RXSNAPHI",
110 "EMAC_PTP_TXSNAPLO", "EMAC_PTP_TXSNAPHI", "EMAC_PTP_ALARMLO",
111 "EMAC_PTP_ALARMHI", "EMAC_PTP_ID_OFF", "EMAC_PTP_ID_SNAP",
112 "EMAC_PTP_PPS_STARTLO", "EMAC_PTP_PPS_STARTHI", "EMAC_PTP_PPS_PERIOD",
113 [mmr_idx (rxc_ok
)] = "EMAC_RXC_OK", "EMAC_RXC_FCS", "EMAC_RXC_LIGN",
114 "EMAC_RXC_OCTET", "EMAC_RXC_DMAOVF", "EMAC_RXC_UNICST", "EMAC_RXC_MULTI",
115 "EMAC_RXC_BROAD", "EMAC_RXC_LNERRI", "EMAC_RXC_LNERRO", "EMAC_RXC_LONG",
116 "EMAC_RXC_MACCTL", "EMAC_RXC_OPCODE", "EMAC_RXC_PAUSE", "EMAC_RXC_ALLFRM",
117 "EMAC_RXC_ALLOCT", "EMAC_RXC_TYPED", "EMAC_RXC_SHORT", "EMAC_RXC_EQ64",
118 "EMAC_RXC_LT128", "EMAC_RXC_LT256", "EMAC_RXC_LT512", "EMAC_RXC_LT1024",
120 [mmr_idx (txc_ok
)] = "EMAC_TXC_OK", "EMAC_TXC_1COL", "EMAC_TXC_GT1COL",
121 "EMAC_TXC_OCTET", "EMAC_TXC_DEFER", "EMAC_TXC_LATECL", "EMAC_TXC_XS_COL",
122 "EMAC_TXC_DMAUND", "EMAC_TXC_CRSERR", "EMAC_TXC_UNICST", "EMAC_TXC_MULTI",
123 "EMAC_TXC_BROAD", "EMAC_TXC_XS_DFR", "EMAC_TXC_MACCTL", "EMAC_TXC_ALLFRM",
124 "EMAC_TXC_ALLOCT", "EMAC_TXC_EQ64", "EMAC_TXC_LT128", "EMAC_TXC_LT256",
125 "EMAC_TXC_LT512", "EMAC_TXC_LT1024", "EMAC_TXC_GE1024", "EMAC_TXC_ABORT",
127 #define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
130 mii_find_phy (struct hw
*me
, bu8 addr
)
132 struct hw
*phy
= hw_child (me
);
133 while (phy
&& --addr
)
134 phy
= hw_sibling (phy
);
139 mii_write (struct hw
*me
)
141 SIM_DESC sd
= hw_system (me
);
142 struct bfin_emac
*emac
= hw_data (me
);
144 bu8 addr
= PHYAD (emac
->staadd
);
145 bu8 reg
= REGAD (emac
->staadd
);
146 bu16 data
= emac
->stadat
;
148 phy
= mii_find_phy (me
, addr
);
151 sim_hw_io_write_buffer (sd
, phy
, &data
, 1, reg
, 2);
155 mii_read (struct hw
*me
)
157 SIM_DESC sd
= hw_system (me
);
158 struct bfin_emac
*emac
= hw_data (me
);
160 bu8 addr
= PHYAD (emac
->staadd
);
161 bu8 reg
= REGAD (emac
->staadd
);
164 phy
= mii_find_phy (me
, addr
);
165 if (!phy
|| sim_hw_io_read_buffer (sd
, phy
, &data
, 1, reg
, 2) != 2)
172 bfin_emac_io_write_buffer (struct hw
*me
, const void *source
,
173 int space
, address_word addr
, unsigned nr_bytes
)
175 struct bfin_emac
*emac
= hw_data (me
);
180 /* Invalid access mode is higher priority than missing register. */
181 /* XXX: 16bit accesses are allowed ... */
182 if (!dv_bfin_mmr_require_32 (me
, addr
, nr_bytes
, true))
184 value
= dv_load_4 (source
);
186 mmr_off
= addr
- emac
->base
;
187 valuep
= (void *)((unsigned long)emac
+ mmr_base() + mmr_off
);
193 case mmr_offset(hashlo
):
194 case mmr_offset(hashhi
):
195 case mmr_offset(stadat
):
196 case mmr_offset(flc
):
197 case mmr_offset(vlan1
):
198 case mmr_offset(vlan2
):
199 case mmr_offset(wkup_ffmsk0
):
200 case mmr_offset(wkup_ffmsk1
):
201 case mmr_offset(wkup_ffmsk2
):
202 case mmr_offset(wkup_ffmsk3
):
203 case mmr_offset(wkup_ffcmd
):
204 case mmr_offset(wkup_ffoff
):
205 case mmr_offset(wkup_ffcrc0
):
206 case mmr_offset(wkup_ffcrc1
):
207 case mmr_offset(sysctl
):
208 case mmr_offset(rx_irqe
):
209 case mmr_offset(tx_irqe
):
210 case mmr_offset(mmc_rirqe
):
211 case mmr_offset(mmc_tirqe
):
214 case mmr_offset(opmode
):
215 if (!(*valuep
& RE
) && (value
& RE
))
216 emac
->rx_stat
&= ~RX_COMP
;
217 if (!(*valuep
& TE
) && (value
& TE
))
218 emac
->tx_stat
&= ~TX_COMP
;
221 case mmr_offset(addrlo
):
222 case mmr_offset(addrhi
):
225 case mmr_offset(wkup_ctl
):
226 dv_w1c_4_partial (valuep
, value
, 0xf20);
228 case mmr_offset(systat
):
229 dv_w1c_4 (valuep
, value
, 0xe1);
231 case mmr_offset(staadd
):
232 *valuep
= value
| STABUSY
;
239 case mmr_offset(rx_stat
):
240 case mmr_offset(tx_stat
):
241 /* Discard writes to these. */
243 case mmr_offset(rx_stky
):
244 case mmr_offset(tx_stky
):
245 case mmr_offset(mmc_rirqs
):
246 case mmr_offset(mmc_tirqs
):
247 dv_w1c_4 (valuep
, value
, -1);
249 case mmr_offset(mmc_ctl
):
250 /* Writing to bit 0 clears all counters. */
251 *valuep
= value
& ~1;
254 memset (&emac
->rxc_ok
, 0, mmr_offset (rxc_ge1024
) - mmr_offset (rxc_ok
) + 4);
255 memset (&emac
->txc_ok
, 0, mmr_offset (txc_abort
) - mmr_offset (txc_ok
) + 4);
258 case mmr_offset(rxc_ok
) ... mmr_offset(rxc_ge1024
):
259 case mmr_offset(txc_ok
) ... mmr_offset(txc_abort
):
260 /* XXX: Are these supposed to be read-only ? */
263 case mmr_offset(ptp_ctl
) ... mmr_offset(ptp_pps_period
):
264 /* XXX: Only on some models; ignore for now. */
267 dv_bfin_mmr_invalid (me
, addr
, nr_bytes
, true);
275 bfin_emac_io_read_buffer (struct hw
*me
, void *dest
,
276 int space
, address_word addr
, unsigned nr_bytes
)
278 struct bfin_emac
*emac
= hw_data (me
);
282 /* Invalid access mode is higher priority than missing register. */
283 /* XXX: 16bit accesses are allowed ... */
284 if (!dv_bfin_mmr_require_32 (me
, addr
, nr_bytes
, false))
287 mmr_off
= addr
- emac
->base
;
288 valuep
= (void *)((unsigned long)emac
+ mmr_base() + mmr_off
);
294 case mmr_offset(opmode
):
295 case mmr_offset(addrlo
):
296 case mmr_offset(addrhi
):
297 case mmr_offset(hashlo
):
298 case mmr_offset(hashhi
):
299 case mmr_offset(staadd
):
300 case mmr_offset(stadat
):
301 case mmr_offset(flc
):
302 case mmr_offset(vlan1
):
303 case mmr_offset(vlan2
):
304 case mmr_offset(wkup_ctl
):
305 case mmr_offset(wkup_ffmsk0
):
306 case mmr_offset(wkup_ffmsk1
):
307 case mmr_offset(wkup_ffmsk2
):
308 case mmr_offset(wkup_ffmsk3
):
309 case mmr_offset(wkup_ffcmd
):
310 case mmr_offset(wkup_ffoff
):
311 case mmr_offset(wkup_ffcrc0
):
312 case mmr_offset(wkup_ffcrc1
):
313 case mmr_offset(sysctl
):
314 case mmr_offset(systat
):
315 case mmr_offset(rx_stat
):
316 case mmr_offset(rx_stky
):
317 case mmr_offset(rx_irqe
):
318 case mmr_offset(tx_stat
):
319 case mmr_offset(tx_stky
):
320 case mmr_offset(tx_irqe
):
321 case mmr_offset(mmc_rirqs
):
322 case mmr_offset(mmc_rirqe
):
323 case mmr_offset(mmc_tirqs
):
324 case mmr_offset(mmc_tirqe
):
325 case mmr_offset(mmc_ctl
):
326 case mmr_offset(rxc_ok
) ... mmr_offset(rxc_ge1024
):
327 case mmr_offset(txc_ok
) ... mmr_offset(txc_abort
):
328 dv_store_4 (dest
, *valuep
);
330 case mmr_offset(ptp_ctl
) ... mmr_offset(ptp_pps_period
):
331 /* XXX: Only on some models; ignore for now. */
334 dv_bfin_mmr_invalid (me
, addr
, nr_bytes
, false);
342 attach_bfin_emac_regs (struct hw
*me
, struct bfin_emac
*emac
)
344 address_word attach_address
;
346 unsigned attach_size
;
347 reg_property_spec reg
;
349 if (hw_find_property (me
, "reg") == NULL
)
350 hw_abort (me
, "Missing \"reg\" property");
352 if (!hw_find_reg_array_property (me
, "reg", 0, ®
))
353 hw_abort (me
, "\"reg\" property must contain three addr/size entries");
355 hw_unit_address_to_attach_address (hw_parent (me
),
357 &attach_space
, &attach_address
, me
);
358 hw_unit_size_to_attach_size (hw_parent (me
), ®
.size
, &attach_size
, me
);
360 if (attach_size
!= BFIN_MMR_EMAC_SIZE
)
361 hw_abort (me
, "\"reg\" size must be %#x", BFIN_MMR_EMAC_SIZE
);
363 hw_attach_address (hw_parent (me
),
364 0, attach_space
, attach_address
, attach_size
, me
);
366 emac
->base
= attach_address
;
369 static struct dv_bfin
*dma_tx
;
372 bfin_emac_dma_read_buffer (struct hw
*me
, void *dest
, int space
,
373 unsigned_word addr
, unsigned nr_bytes
)
375 struct bfin_emac
*emac
= hw_data (me
);
376 struct dv_bfin
*dma
= hw_data (emac
->dma_master
);
377 unsigned char *data
= dest
;
378 static bool flop
; /* XXX: This sucks. */
382 HW_TRACE_DMA_READ ();
386 /* Handle the TX turn around and write the status. */
387 emac
->tx_stat
|= TX_OK
;
388 emac
->tx_stky
|= TX_OK
;
390 memcpy (data
, &emac
->tx_stat
, 4);
396 if (!(emac
->opmode
& RE
))
402 /* Outgoing DMA buffer has 16bit len prepended to it. */
405 /* This doesn't seem to work.
406 if (emac->sysctl & RXDWA)
412 ret
= read (emac
->tap
, data
, nr_bytes
);
415 ret
+= 4; /* include crc */
416 pad_ret
= max (ret
+ 4, 64);
418 memcpy (dest
, &len
, 2);
420 pad_ret
= (pad_ret
+ 3) & ~3;
422 memset (data
+ ret
, 0, pad_ret
- ret
);
425 /* XXX: Need to check -- u-boot doesn't look at this. */
426 if (emac
->sysctl
& RXCKS
)
433 /* XXX: Don't support promiscuous yet. */
434 emac
->rx_stat
|= RX_ACCEPT
;
435 emac
->rx_stat
= (emac
->rx_stat
& ~RX_FRLEN
) | len
;
437 emac
->rx_stat
|= RX_COMP
;
438 emac
->rx_stky
|= RX_COMP
;
442 /* Write the RX status and crc info. */
443 emac
->rx_stat
|= RX_OK
;
444 emac
->rx_stky
|= RX_OK
;
447 if (emac
->sysctl
& RXCKS
)
449 memcpy (data
, &emac
->rx_crc
, 4);
453 memcpy (data
, &emac
->rx_stat
, 4);
462 bfin_emac_dma_write_buffer (struct hw
*me
, const void *source
,
463 int space
, unsigned_word addr
,
465 int violate_read_only_section
)
467 struct bfin_emac
*emac
= hw_data (me
);
468 struct dv_bfin
*dma
= hw_data (emac
->dma_master
);
469 const unsigned char *data
= source
;
473 HW_TRACE_DMA_WRITE ();
475 if (!(emac
->opmode
& TE
))
478 /* Incoming DMA buffer has 16bit len prepended to it. */
479 memcpy (&len
, data
, 2);
483 ret
= write (emac
->tap
, data
+ 2, len
);
488 emac
->tx_stat
|= TX_COMP
;
489 emac
->tx_stky
|= TX_COMP
;
496 static const struct hw_port_descriptor bfin_emac_ports
[] =
498 { "tx", DV_PORT_TX
, 0, output_port
, },
499 { "rx", DV_PORT_RX
, 0, output_port
, },
500 { "stat", DV_PORT_STAT
, 0, output_port
, },
505 bfin_emac_attach_address_callback (struct hw
*me
,
509 address_word nr_bytes
,
512 const hw_unit
*unit
= hw_unit_address (client
);
513 HW_TRACE ((me
, "attach - level=%d, space=%d, addr=0x%lx, nr_bytes=%lu, client=%s",
514 level
, space
, (unsigned long) addr
, (unsigned long) nr_bytes
, hw_path (client
)));
515 /* NOTE: At preset the space is assumed to be zero. Perhaphs the
516 space should be mapped onto something for instance: space0 -
517 unified memory; space1 - IO memory; ... */
518 sim_core_attach (hw_system (me
),
520 level
+ 10 + unit
->cells
[unit
->nr_cells
- 1],
521 access_read_write_exec
,
530 bfin_emac_delete (struct hw
*me
)
532 struct bfin_emac
*emac
= hw_data (me
);
537 bfin_emac_tap_init (struct hw
*me
)
540 struct bfin_emac
*emac
= hw_data (me
);
544 unit
= hw_unit_address (me
);
546 emac
->tap
= open ("/dev/net/tun", O_RDWR
);
549 HW_TRACE ((me
, "unable to open /dev/net/tun: %s", strerror (errno
)));
553 memset (&emac
->ifr
, 0, sizeof (emac
->ifr
));
554 emac
->ifr
.ifr_flags
= IFF_TAP
| IFF_NO_PI
;
555 strcpy (emac
->ifr
.ifr_name
, "tap-gdb");
557 flags
= 1 * 1024 * 1024;
558 if (ioctl (emac
->tap
, TUNSETIFF
, &emac
->ifr
) < 0
560 || ioctl (emac
->tap
, TUNSETNOCSUM
) < 0
563 || ioctl (emac
->tap
, TUNSETSNDBUF
, &flags
) < 0
567 HW_TRACE ((me
, "tap ioctl setup failed: %s", strerror (errno
)));
572 flags
= fcntl (emac
->tap
, F_GETFL
);
573 fcntl (emac
->tap
, F_SETFL
, flags
| O_NONBLOCK
);
578 bfin_emac_finish (struct hw
*me
)
580 struct bfin_emac
*emac
;
582 emac
= HW_ZALLOC (me
, struct bfin_emac
);
584 set_hw_data (me
, emac
);
585 set_hw_io_read_buffer (me
, bfin_emac_io_read_buffer
);
586 set_hw_io_write_buffer (me
, bfin_emac_io_write_buffer
);
587 set_hw_dma_read_buffer (me
, bfin_emac_dma_read_buffer
);
588 set_hw_dma_write_buffer (me
, bfin_emac_dma_write_buffer
);
589 set_hw_ports (me
, bfin_emac_ports
);
590 set_hw_attach_address (me
, bfin_emac_attach_address_callback
);
591 set_hw_delete (me
, bfin_emac_delete
);
593 attach_bfin_emac_regs (me
, emac
);
595 /* Initialize the EMAC. */
596 emac
->addrlo
= 0xffffffff;
597 emac
->addrhi
= 0x0000ffff;
598 emac
->vlan1
= 0x0000ffff;
599 emac
->vlan2
= 0x0000ffff;
600 emac
->sysctl
= 0x00003f00;
601 emac
->mmc_ctl
= 0x0000000a;
603 bfin_emac_tap_init (me
);
606 const struct hw_descriptor dv_bfin_emac_descriptor
[] =
608 {"bfin_emac", bfin_emac_finish
,},