Blame sim/bfin/dv-eth_phy.c

Packit Service 706eca
/* Ethernet Physical Receiver model.
Packit Service 706eca
Packit Service 706eca
   Copyright (C) 2010-2018 Free Software Foundation, Inc.
Packit Service 706eca
   Contributed by Analog Devices, Inc.
Packit Service 706eca
Packit Service 706eca
   This file is part of simulators.
Packit Service 706eca
Packit Service 706eca
   This program is free software; you can redistribute it and/or modify
Packit Service 706eca
   it under the terms of the GNU General Public License as published by
Packit Service 706eca
   the Free Software Foundation; either version 3 of the License, or
Packit Service 706eca
   (at your option) any later version.
Packit Service 706eca
Packit Service 706eca
   This program is distributed in the hope that it will be useful,
Packit Service 706eca
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 706eca
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 706eca
   GNU General Public License for more details.
Packit Service 706eca
Packit Service 706eca
   You should have received a copy of the GNU General Public License
Packit Service 706eca
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Service 706eca
Packit Service 706eca
#include "config.h"
Packit Service 706eca
Packit Service 706eca
#include "sim-main.h"
Packit Service 706eca
#include "devices.h"
Packit Service 706eca
Packit Service 706eca
#if defined (HAVE_LINUX_MII_H) && defined (HAVE_LINUX_TYPES_H)
Packit Service 706eca
Packit Service 706eca
/* Workaround old/broken linux headers.  */
Packit Service 706eca
#include <linux/types.h>
Packit Service 706eca
#include <linux/mii.h>
Packit Service 706eca
Packit Service 706eca
#define REG_PHY_SIZE 0x20
Packit Service 706eca
Packit Service 706eca
struct eth_phy
Packit Service 706eca
{
Packit Service 706eca
  bu32 base;
Packit Service 706eca
  bu16 regs[REG_PHY_SIZE];
Packit Service 706eca
};
Packit Service 706eca
#define reg_base()      offsetof(struct eth_phy, regs[0])
Packit Service 706eca
#define reg_offset(reg) (offsetof(struct eth_phy, reg) - reg_base())
Packit Service 706eca
#define reg_idx(reg)    (reg_offset (reg) / 4)
Packit Service 706eca
Packit Service 706eca
static const char * const reg_names[] =
Packit Service 706eca
{
Packit Service 706eca
  [MII_BMCR       ] = "MII_BMCR",
Packit Service 706eca
  [MII_BMSR       ] = "MII_BMSR",
Packit Service 706eca
  [MII_PHYSID1    ] = "MII_PHYSID1",
Packit Service 706eca
  [MII_PHYSID2    ] = "MII_PHYSID2",
Packit Service 706eca
  [MII_ADVERTISE  ] = "MII_ADVERTISE",
Packit Service 706eca
  [MII_LPA        ] = "MII_LPA",
Packit Service 706eca
  [MII_EXPANSION  ] = "MII_EXPANSION",
Packit Service 706eca
#ifdef MII_CTRL1000
Packit Service 706eca
  [MII_CTRL1000   ] = "MII_CTRL1000",
Packit Service 706eca
#endif
Packit Service 706eca
#ifdef MII_STAT1000
Packit Service 706eca
  [MII_STAT1000   ] = "MII_STAT1000",
Packit Service 706eca
#endif
Packit Service 706eca
#ifdef MII_ESTATUS
Packit Service 706eca
  [MII_ESTATUS    ] = "MII_ESTATUS",
Packit Service 706eca
#endif
Packit Service 706eca
  [MII_DCOUNTER   ] = "MII_DCOUNTER",
Packit Service 706eca
  [MII_FCSCOUNTER ] = "MII_FCSCOUNTER",
Packit Service 706eca
  [MII_NWAYTEST   ] = "MII_NWAYTEST",
Packit Service 706eca
  [MII_RERRCOUNTER] = "MII_RERRCOUNTER",
Packit Service 706eca
  [MII_SREVISION  ] = "MII_SREVISION",
Packit Service 706eca
  [MII_RESV1      ] = "MII_RESV1",
Packit Service 706eca
  [MII_LBRERROR   ] = "MII_LBRERROR",
Packit Service 706eca
  [MII_PHYADDR    ] = "MII_PHYADDR",
Packit Service 706eca
  [MII_RESV2      ] = "MII_RESV2",
Packit Service 706eca
  [MII_TPISTATUS  ] = "MII_TPISTATUS",
Packit Service 706eca
  [MII_NCONFIG    ] = "MII_NCONFIG",
Packit Service 706eca
};
Packit Service 706eca
#define mmr_name(off) (reg_names[off] ? : "<INV>")
Packit Service 706eca
#define mmr_off reg_off
Packit Service 706eca
Packit Service 706eca
static unsigned
Packit Service 706eca
eth_phy_io_write_buffer (struct hw *me, const void *source,
Packit Service 706eca
			 int space, address_word addr, unsigned nr_bytes)
Packit Service 706eca
{
Packit Service 706eca
  struct eth_phy *phy = hw_data (me);
Packit Service 706eca
  bu16 reg_off;
Packit Service 706eca
  bu16 value;
Packit Service 706eca
  bu16 *valuep;
Packit Service 706eca
Packit Service 706eca
  value = dv_load_2 (source);
Packit Service 706eca
Packit Service 706eca
  reg_off = addr - phy->base;
Packit Service 706eca
  valuep = (void *)((unsigned long)phy + reg_base() + reg_off);
Packit Service 706eca
Packit Service 706eca
  HW_TRACE_WRITE ();
Packit Service 706eca
Packit Service 706eca
  switch (reg_off)
Packit Service 706eca
    {
Packit Service 706eca
    case MII_BMCR:
Packit Service 706eca
      *valuep = value;
Packit Service 706eca
      break;
Packit Service 706eca
    case MII_PHYSID1:
Packit Service 706eca
    case MII_PHYSID2:
Packit Service 706eca
      /* Discard writes to these.  */
Packit Service 706eca
      break;
Packit Service 706eca
    default:
Packit Service 706eca
      /* XXX: Discard writes to unknown regs ?  */
Packit Service 706eca
      *valuep = value;
Packit Service 706eca
      break;
Packit Service 706eca
    }
Packit Service 706eca
Packit Service 706eca
  return nr_bytes;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
static unsigned
Packit Service 706eca
eth_phy_io_read_buffer (struct hw *me, void *dest,
Packit Service 706eca
			int space, address_word addr, unsigned nr_bytes)
Packit Service 706eca
{
Packit Service 706eca
  struct eth_phy *phy = hw_data (me);
Packit Service 706eca
  bu16 reg_off;
Packit Service 706eca
  bu16 *valuep;
Packit Service 706eca
Packit Service 706eca
  reg_off = addr - phy->base;
Packit Service 706eca
  valuep = (void *)((unsigned long)phy + reg_base() + reg_off);
Packit Service 706eca
Packit Service 706eca
  HW_TRACE_READ ();
Packit Service 706eca
Packit Service 706eca
  switch (reg_off)
Packit Service 706eca
    {
Packit Service 706eca
    case MII_BMCR:
Packit Service 706eca
      dv_store_2 (dest, *valuep);
Packit Service 706eca
      break;
Packit Service 706eca
    case MII_BMSR:
Packit Service 706eca
      /* XXX: Let people control this ?  */
Packit Service 706eca
      *valuep = BMSR_100FULL | BMSR_100HALF | BMSR_10FULL | BMSR_10HALF |
Packit Service 706eca
		BMSR_ANEGCOMPLETE | BMSR_ANEGCAPABLE | BMSR_LSTATUS;
Packit Service 706eca
      dv_store_2 (dest, *valuep);
Packit Service 706eca
      break;
Packit Service 706eca
    case MII_LPA:
Packit Service 706eca
      /* XXX: Let people control this ?  */
Packit Service 706eca
      *valuep = LPA_100FULL | LPA_100HALF | LPA_10FULL | LPA_10HALF;
Packit Service 706eca
      dv_store_2 (dest, *valuep);
Packit Service 706eca
      break;
Packit Service 706eca
    default:
Packit Service 706eca
      dv_store_2 (dest, *valuep);
Packit Service 706eca
      break;
Packit Service 706eca
    }
Packit Service 706eca
Packit Service 706eca
  return nr_bytes;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
static void
Packit Service 706eca
attach_eth_phy_regs (struct hw *me, struct eth_phy *phy)
Packit Service 706eca
{
Packit Service 706eca
  address_word attach_address;
Packit Service 706eca
  int attach_space;
Packit Service 706eca
  unsigned attach_size;
Packit Service 706eca
  reg_property_spec reg;
Packit Service 706eca
Packit Service 706eca
  if (hw_find_property (me, "reg") == NULL)
Packit Service 706eca
    hw_abort (me, "Missing \"reg\" property");
Packit Service 706eca
Packit Service 706eca
  if (!hw_find_reg_array_property (me, "reg", 0, &reg))
Packit Service 706eca
    hw_abort (me, "\"reg\" property must contain three addr/size entries");
Packit Service 706eca
Packit Service 706eca
  hw_unit_address_to_attach_address (hw_parent (me),
Packit Service 706eca
				     &reg.address,
Packit Service 706eca
				     &attach_space, &attach_address, me);
Packit Service 706eca
  hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
Packit Service 706eca
Packit Service 706eca
  if (attach_size != REG_PHY_SIZE)
Packit Service 706eca
    hw_abort (me, "\"reg\" size must be %#x", REG_PHY_SIZE);
Packit Service 706eca
Packit Service 706eca
  hw_attach_address (hw_parent (me),
Packit Service 706eca
		     0, attach_space, attach_address, attach_size, me);
Packit Service 706eca
Packit Service 706eca
  phy->base = attach_address;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
static void
Packit Service 706eca
eth_phy_finish (struct hw *me)
Packit Service 706eca
{
Packit Service 706eca
  struct eth_phy *phy;
Packit Service 706eca
Packit Service 706eca
  phy = HW_ZALLOC (me, struct eth_phy);
Packit Service 706eca
Packit Service 706eca
  set_hw_data (me, phy);
Packit Service 706eca
  set_hw_io_read_buffer (me, eth_phy_io_read_buffer);
Packit Service 706eca
  set_hw_io_write_buffer (me, eth_phy_io_write_buffer);
Packit Service 706eca
Packit Service 706eca
  attach_eth_phy_regs (me, phy);
Packit Service 706eca
Packit Service 706eca
  /* Initialize the PHY.  */
Packit Service 706eca
  phy->regs[MII_PHYSID1] = 0;    /* Unassigned Vendor */
Packit Service 706eca
  phy->regs[MII_PHYSID2] = 0xAD; /* Product */
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
#else
Packit Service 706eca
Packit Service 706eca
static void
Packit Service 706eca
eth_phy_finish (struct hw *me)
Packit Service 706eca
{
Packit Service 706eca
  HW_TRACE ((me, "No linux/mii.h support found"));
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
#endif
Packit Service 706eca
Packit Service 706eca
const struct hw_descriptor dv_eth_phy_descriptor[] =
Packit Service 706eca
{
Packit Service 706eca
  {"eth_phy", eth_phy_finish,},
Packit Service 706eca
  {NULL, NULL},
Packit Service 706eca
};