1/* Blackfin Ethernet Media Access Controller (EMAC) model.
2
3   Copyright (C) 2010-2011 Free Software Foundation, Inc.
4   Contributed by Analog Devices, Inc.
5
6   This file is part of simulators.
7
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.
12
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.
17
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/>.  */
20
21#include "config.h"
22
23#include <errno.h>
24#include <fcntl.h>
25#include <unistd.h>
26
27#ifdef HAVE_SYS_IOCTL_H
28#include <sys/ioctl.h>
29#endif
30#ifdef HAVE_NET_IF_H
31#include <net/if.h>
32#endif
33#ifdef HAVE_LINUX_IF_TUN_H
34#include <linux/if_tun.h>
35#endif
36
37#ifdef HAVE_LINUX_IF_TUN_H
38# define WITH_TUN 1
39#else
40# define WITH_TUN 0
41#endif
42
43#include "sim-main.h"
44#include "sim-hw.h"
45#include "devices.h"
46#include "dv-bfin_emac.h"
47
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.  */
51
52struct bfin_emac
53{
54  /* This top portion matches common dv_bfin struct.  */
55  bu32 base;
56  struct hw *dma_master;
57  bool acked;
58
59  int tap;
60#if WITH_TUN
61  struct ifreq ifr;
62#endif
63  bu32 rx_crc;
64
65  /* Order after here is important -- matches hardware MMR layout.  */
66  bu32 opmode, addrlo, addrhi, hashlo, hashhi, staadd, stadat, flc, vlan1, vlan2;
67  bu32 _pad0;
68  bu32 wkup_ctl, wkup_ffmsk0, wkup_ffmsk1, wkup_ffmsk2, wkup_ffmsk3;
69  bu32 wkup_ffcmd, wkup_ffoff, wkup_ffcrc0, wkup_ffcrc1;
70  bu32 _pad1[4];
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;
73  bu32 _pad2[3];
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;
81  bu32 _pad3[1];
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;
86  bu32 _pad4[8];
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;
91};
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)
95
96static const char * const mmr_names[BFIN_MMR_EMAC_SIZE / 4] =
97{
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",
119  "EMAC_RXC_GE1024",
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",
126};
127#define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
128
129static struct hw *
130mii_find_phy (struct hw *me, bu8 addr)
131{
132  struct hw *phy = hw_child (me);
133  while (phy && --addr)
134    phy = hw_sibling (phy);
135  return phy;
136}
137
138static void
139mii_write (struct hw *me)
140{
141  SIM_DESC sd = hw_system (me);
142  struct bfin_emac *emac = hw_data (me);
143  struct hw *phy;
144  bu8 addr = PHYAD (emac->staadd);
145  bu8 reg = REGAD (emac->staadd);
146  bu16 data = emac->stadat;
147
148  phy = mii_find_phy (me, addr);
149  if (!phy)
150    return;
151  sim_hw_io_write_buffer (sd, phy, &data, 1, reg, 2);
152}
153
154static void
155mii_read (struct hw *me)
156{
157  SIM_DESC sd = hw_system (me);
158  struct bfin_emac *emac = hw_data (me);
159  struct hw *phy;
160  bu8 addr = PHYAD (emac->staadd);
161  bu8 reg = REGAD (emac->staadd);
162  bu16 data;
163
164  phy = mii_find_phy (me, addr);
165  if (!phy || sim_hw_io_read_buffer (sd, phy, &data, 1, reg, 2) != 2)
166    data = 0xffff;
167
168  emac->stadat = data;
169}
170
171static unsigned
172bfin_emac_io_write_buffer (struct hw *me, const void *source,
173			   int space, address_word addr, unsigned nr_bytes)
174{
175  struct bfin_emac *emac = hw_data (me);
176  bu32 mmr_off;
177  bu32 value;
178  bu32 *valuep;
179
180  /* XXX: 16bit accesses are allowed ...  */
181  dv_bfin_mmr_require_32 (me, addr, nr_bytes, true);
182  value = dv_load_4 (source);
183
184  mmr_off = addr - emac->base;
185  valuep = (void *)((unsigned long)emac + mmr_base() + mmr_off);
186
187  HW_TRACE_WRITE ();
188
189  switch (mmr_off)
190    {
191    case mmr_offset(hashlo):
192    case mmr_offset(hashhi):
193    case mmr_offset(stadat):
194    case mmr_offset(flc):
195    case mmr_offset(vlan1):
196    case mmr_offset(vlan2):
197    case mmr_offset(wkup_ffmsk0):
198    case mmr_offset(wkup_ffmsk1):
199    case mmr_offset(wkup_ffmsk2):
200    case mmr_offset(wkup_ffmsk3):
201    case mmr_offset(wkup_ffcmd):
202    case mmr_offset(wkup_ffoff):
203    case mmr_offset(wkup_ffcrc0):
204    case mmr_offset(wkup_ffcrc1):
205    case mmr_offset(sysctl):
206    case mmr_offset(rx_irqe):
207    case mmr_offset(tx_irqe):
208    case mmr_offset(mmc_rirqe):
209    case mmr_offset(mmc_tirqe):
210      *valuep = value;
211      break;
212    case mmr_offset(opmode):
213      if (!(*valuep & RE) && (value & RE))
214	emac->rx_stat &= ~RX_COMP;
215      if (!(*valuep & TE) && (value & TE))
216	emac->tx_stat &= ~TX_COMP;
217      *valuep = value;
218      break;
219    case mmr_offset(addrlo):
220    case mmr_offset(addrhi):
221      *valuep = value;
222      break;
223    case mmr_offset(wkup_ctl):
224      dv_w1c_4_partial (valuep, value, 0xf20);
225      break;
226    case mmr_offset(systat):
227      dv_w1c_4 (valuep, value, 0xe1);
228      break;
229    case mmr_offset(staadd):
230      *valuep = value | STABUSY;
231      if (value & STAOP)
232	mii_write (me);
233      else
234	mii_read (me);
235      *valuep &= ~STABUSY;
236      break;
237    case mmr_offset(rx_stat):
238    case mmr_offset(tx_stat):
239      /* Discard writes to these.  */
240      break;
241    case mmr_offset(rx_stky):
242    case mmr_offset(tx_stky):
243    case mmr_offset(mmc_rirqs):
244    case mmr_offset(mmc_tirqs):
245      dv_w1c_4 (valuep, value, -1);
246      break;
247    case mmr_offset(mmc_ctl):
248      /* Writing to bit 0 clears all counters.  */
249      *valuep = value & ~1;
250      if (value & 1)
251	{
252	  memset (&emac->rxc_ok, 0, mmr_offset (rxc_ge1024) - mmr_offset (rxc_ok) + 4);
253	  memset (&emac->txc_ok, 0, mmr_offset (txc_abort) - mmr_offset (txc_ok) + 4);
254	}
255      break;
256    case mmr_offset(rxc_ok) ... mmr_offset(rxc_ge1024):
257    case mmr_offset(txc_ok) ... mmr_offset(txc_abort):
258      /* XXX: Are these supposed to be read-only ?  */
259      *valuep = value;
260      break;
261    case mmr_offset(ptp_ctl) ... mmr_offset(ptp_pps_period):
262      /* XXX: Only on some models; ignore for now.  */
263      break;
264    default:
265      dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
266      break;
267    }
268
269  return nr_bytes;
270}
271
272static unsigned
273bfin_emac_io_read_buffer (struct hw *me, void *dest,
274			  int space, address_word addr, unsigned nr_bytes)
275{
276  struct bfin_emac *emac = hw_data (me);
277  bu32 mmr_off;
278  bu32 *valuep;
279
280  /* XXX: 16bit accesses are allowed ...  */
281  dv_bfin_mmr_require_32 (me, addr, nr_bytes, false);
282
283  mmr_off = addr - emac->base;
284  valuep = (void *)((unsigned long)emac + mmr_base() + mmr_off);
285
286  HW_TRACE_READ ();
287
288  switch (mmr_off)
289    {
290    case mmr_offset(opmode):
291    case mmr_offset(addrlo):
292    case mmr_offset(addrhi):
293    case mmr_offset(hashlo):
294    case mmr_offset(hashhi):
295    case mmr_offset(staadd):
296    case mmr_offset(stadat):
297    case mmr_offset(flc):
298    case mmr_offset(vlan1):
299    case mmr_offset(vlan2):
300    case mmr_offset(wkup_ctl):
301    case mmr_offset(wkup_ffmsk0):
302    case mmr_offset(wkup_ffmsk1):
303    case mmr_offset(wkup_ffmsk2):
304    case mmr_offset(wkup_ffmsk3):
305    case mmr_offset(wkup_ffcmd):
306    case mmr_offset(wkup_ffoff):
307    case mmr_offset(wkup_ffcrc0):
308    case mmr_offset(wkup_ffcrc1):
309    case mmr_offset(sysctl):
310    case mmr_offset(systat):
311    case mmr_offset(rx_stat):
312    case mmr_offset(rx_stky):
313    case mmr_offset(rx_irqe):
314    case mmr_offset(tx_stat):
315    case mmr_offset(tx_stky):
316    case mmr_offset(tx_irqe):
317    case mmr_offset(mmc_rirqs):
318    case mmr_offset(mmc_rirqe):
319    case mmr_offset(mmc_tirqs):
320    case mmr_offset(mmc_tirqe):
321    case mmr_offset(mmc_ctl):
322    case mmr_offset(rxc_ok) ... mmr_offset(rxc_ge1024):
323    case mmr_offset(txc_ok) ... mmr_offset(txc_abort):
324      dv_store_4 (dest, *valuep);
325      break;
326    case mmr_offset(ptp_ctl) ... mmr_offset(ptp_pps_period):
327      /* XXX: Only on some models; ignore for now.  */
328      break;
329    default:
330      dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
331      break;
332    }
333
334  return nr_bytes;
335}
336
337static void
338attach_bfin_emac_regs (struct hw *me, struct bfin_emac *emac)
339{
340  address_word attach_address;
341  int attach_space;
342  unsigned attach_size;
343  reg_property_spec reg;
344
345  if (hw_find_property (me, "reg") == NULL)
346    hw_abort (me, "Missing \"reg\" property");
347
348  if (!hw_find_reg_array_property (me, "reg", 0, &reg))
349    hw_abort (me, "\"reg\" property must contain three addr/size entries");
350
351  hw_unit_address_to_attach_address (hw_parent (me),
352				     &reg.address,
353				     &attach_space, &attach_address, me);
354  hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
355
356  if (attach_size != BFIN_MMR_EMAC_SIZE)
357    hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_EMAC_SIZE);
358
359  hw_attach_address (hw_parent (me),
360		     0, attach_space, attach_address, attach_size, me);
361
362  emac->base = attach_address;
363}
364
365static struct dv_bfin *dma_tx;
366
367static unsigned
368bfin_emac_dma_read_buffer (struct hw *me, void *dest, int space,
369			   unsigned_word addr, unsigned nr_bytes)
370{
371  struct bfin_emac *emac = hw_data (me);
372  struct dv_bfin *dma = hw_data (emac->dma_master);
373  unsigned char *data = dest;
374  static bool flop; /* XXX: This sucks.  */
375  bu16 len;
376  ssize_t ret;
377
378  HW_TRACE_DMA_READ ();
379
380  if (dma_tx == dma)
381    {
382      /* Handle the TX turn around and write the status.  */
383      emac->tx_stat |= TX_OK;
384      emac->tx_stky |= TX_OK;
385
386      memcpy (data, &emac->tx_stat, 4);
387
388      dma->acked = true;
389      return 4;
390    }
391
392  if (!(emac->opmode & RE))
393    return 0;
394
395  if (!flop)
396    {
397      ssize_t pad_ret;
398      /* Outgoing DMA buffer has 16bit len prepended to it.  */
399      data += 2;
400
401      /* This doesn't seem to work.
402      if (emac->sysctl & RXDWA)
403	{
404	  memset (data, 0, 2);
405	  data += 2;
406	} */
407
408      ret = read (emac->tap, data, nr_bytes);
409      if (ret < 0)
410	return 0;
411      ret += 4; /* include crc */
412      pad_ret = MAX (ret + 4, 64);
413      len = pad_ret;
414      memcpy (dest, &len, 2);
415
416      pad_ret = (pad_ret + 3) & ~3;
417      if (ret < pad_ret)
418	memset (data + ret, 0, pad_ret - ret);
419      pad_ret += 4;
420
421      /* XXX: Need to check -- u-boot doesn't look at this.  */
422      if (emac->sysctl & RXCKS)
423	{
424	  pad_ret += 4;
425	  emac->rx_crc = 0;
426	}
427      ret = pad_ret;
428
429      /* XXX: Don't support promiscuous yet.  */
430      emac->rx_stat |= RX_ACCEPT;
431      emac->rx_stat = (emac->rx_stat & ~RX_FRLEN) | len;
432
433      emac->rx_stat |= RX_COMP;
434      emac->rx_stky |= RX_COMP;
435    }
436  else
437    {
438      /* Write the RX status and crc info.  */
439      emac->rx_stat |= RX_OK;
440      emac->rx_stky |= RX_OK;
441
442      ret = 4;
443      if (emac->sysctl & RXCKS)
444	{
445	  memcpy (data, &emac->rx_crc, 4);
446	  data += 4;
447	  ret += 4;
448	}
449      memcpy (data, &emac->rx_stat, 4);
450    }
451
452  flop = !flop;
453  dma->acked = true;
454  return ret;
455}
456
457static unsigned
458bfin_emac_dma_write_buffer (struct hw *me, const void *source,
459			    int space, unsigned_word addr,
460			    unsigned nr_bytes,
461			    int violate_read_only_section)
462{
463  struct bfin_emac *emac = hw_data (me);
464  struct dv_bfin *dma = hw_data (emac->dma_master);
465  const unsigned char *data = source;
466  bu16 len;
467  ssize_t ret;
468
469  HW_TRACE_DMA_WRITE ();
470
471  if (!(emac->opmode & TE))
472    return 0;
473
474  /* Incoming DMA buffer has 16bit len prepended to it.  */
475  memcpy (&len, data, 2);
476  if (!len)
477    return 0;
478
479  ret = write (emac->tap, data + 2, len);
480  if (ret < 0)
481    return 0;
482  ret += 2;
483
484  emac->tx_stat |= TX_COMP;
485  emac->tx_stky |= TX_COMP;
486
487  dma_tx = dma;
488  dma->acked = true;
489  return ret;
490}
491
492static const struct hw_port_descriptor bfin_emac_ports[] =
493{
494  { "tx",   DV_PORT_TX,   0, output_port, },
495  { "rx",   DV_PORT_RX,   0, output_port, },
496  { "stat", DV_PORT_STAT, 0, output_port, },
497  { NULL, 0, 0, 0, },
498};
499
500static void
501bfin_emac_attach_address_callback (struct hw *me,
502				   int level,
503				   int space,
504				   address_word addr,
505				   address_word nr_bytes,
506				   struct hw *client)
507{
508  const hw_unit *unit = hw_unit_address (client);
509  HW_TRACE ((me, "attach - level=%d, space=%d, addr=0x%lx, nr_bytes=%lu, client=%s",
510	     level, space, (unsigned long) addr, (unsigned long) nr_bytes, hw_path (client)));
511  /* NOTE: At preset the space is assumed to be zero.  Perhaphs the
512     space should be mapped onto something for instance: space0 -
513     unified memory; space1 - IO memory; ... */
514  sim_core_attach (hw_system (me),
515		   NULL, /*cpu*/
516		   level + 10 + unit->cells[unit->nr_cells - 1],
517		   access_read_write_exec,
518		   space, addr,
519		   nr_bytes,
520		   0, /* modulo */
521		   client,
522		   NULL);
523}
524
525static void
526bfin_emac_delete (struct hw *me)
527{
528  struct bfin_emac *emac = hw_data (me);
529  close (emac->tap);
530}
531
532static void
533bfin_emac_tap_init (struct hw *me)
534{
535#if WITH_TUN
536  struct bfin_emac *emac = hw_data (me);
537  const hw_unit *unit;
538  int flags;
539
540  unit = hw_unit_address (me);
541
542  emac->tap = open ("/dev/net/tun", O_RDWR);
543  if (emac->tap == -1)
544    {
545      HW_TRACE ((me, "unable to open /dev/net/tun: %s", strerror (errno)));
546      return;
547    }
548
549  memset (&emac->ifr, 0, sizeof (emac->ifr));
550  emac->ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
551  strcpy (emac->ifr.ifr_name, "tap-gdb");
552
553  flags = 1 * 1024 * 1024;
554  if (ioctl (emac->tap, TUNSETIFF, &emac->ifr) < 0
555#ifdef TUNSETNOCSUM
556      || ioctl (emac->tap, TUNSETNOCSUM) < 0
557#endif
558#ifdef TUNSETSNDBUF
559      || ioctl (emac->tap, TUNSETSNDBUF, &flags) < 0
560#endif
561     )
562    {
563      HW_TRACE ((me, "tap ioctl setup failed: %s", strerror (errno)));
564      close (emac->tap);
565      return;
566    }
567
568  flags = fcntl (emac->tap, F_GETFL);
569  fcntl (emac->tap, F_SETFL, flags | O_NONBLOCK);
570#endif
571}
572
573static void
574bfin_emac_finish (struct hw *me)
575{
576  struct bfin_emac *emac;
577
578  emac = HW_ZALLOC (me, struct bfin_emac);
579
580  set_hw_data (me, emac);
581  set_hw_io_read_buffer (me, bfin_emac_io_read_buffer);
582  set_hw_io_write_buffer (me, bfin_emac_io_write_buffer);
583  set_hw_dma_read_buffer (me, bfin_emac_dma_read_buffer);
584  set_hw_dma_write_buffer (me, bfin_emac_dma_write_buffer);
585  set_hw_ports (me, bfin_emac_ports);
586  set_hw_attach_address (me, bfin_emac_attach_address_callback);
587  set_hw_delete (me, bfin_emac_delete);
588
589  attach_bfin_emac_regs (me, emac);
590
591  /* Initialize the EMAC.  */
592  emac->addrlo = 0xffffffff;
593  emac->addrhi = 0x0000ffff;
594  emac->vlan1 = 0x0000ffff;
595  emac->vlan2 = 0x0000ffff;
596  emac->sysctl = 0x00003f00;
597  emac->mmc_ctl = 0x0000000a;
598
599  bfin_emac_tap_init (me);
600}
601
602const struct hw_descriptor dv_bfin_emac_descriptor[] =
603{
604  {"bfin_emac", bfin_emac_finish,},
605  {NULL, NULL},
606};
607