Home | History | Annotate | Line # | Download | only in bfin
dv-eth_phy.c revision 1.1
      1 /* Ethernet Physical Receiver model.
      2 
      3    Copyright (C) 2010-2014 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 "sim-main.h"
     24 #include "devices.h"
     25 
     26 #if defined (HAVE_LINUX_MII_H) && defined (HAVE_LINUX_TYPES_H)
     27 
     28 /* Workaround old/broken linux headers.  */
     29 #include <linux/types.h>
     30 #include <linux/mii.h>
     31 
     32 #define REG_PHY_SIZE 0x20
     33 
     34 struct eth_phy
     35 {
     36   bu32 base;
     37   bu16 regs[REG_PHY_SIZE];
     38 };
     39 #define reg_base()      offsetof(struct eth_phy, regs[0])
     40 #define reg_offset(reg) (offsetof(struct eth_phy, reg) - reg_base())
     41 #define reg_idx(reg)    (reg_offset (reg) / 4)
     42 
     43 static const char * const reg_names[] =
     44 {
     45   [MII_BMCR       ] = "MII_BMCR",
     46   [MII_BMSR       ] = "MII_BMSR",
     47   [MII_PHYSID1    ] = "MII_PHYSID1",
     48   [MII_PHYSID2    ] = "MII_PHYSID2",
     49   [MII_ADVERTISE  ] = "MII_ADVERTISE",
     50   [MII_LPA        ] = "MII_LPA",
     51   [MII_EXPANSION  ] = "MII_EXPANSION",
     52 #ifdef MII_CTRL1000
     53   [MII_CTRL1000   ] = "MII_CTRL1000",
     54 #endif
     55 #ifdef MII_STAT1000
     56   [MII_STAT1000   ] = "MII_STAT1000",
     57 #endif
     58 #ifdef MII_ESTATUS
     59   [MII_ESTATUS    ] = "MII_ESTATUS",
     60 #endif
     61   [MII_DCOUNTER   ] = "MII_DCOUNTER",
     62   [MII_FCSCOUNTER ] = "MII_FCSCOUNTER",
     63   [MII_NWAYTEST   ] = "MII_NWAYTEST",
     64   [MII_RERRCOUNTER] = "MII_RERRCOUNTER",
     65   [MII_SREVISION  ] = "MII_SREVISION",
     66   [MII_RESV1      ] = "MII_RESV1",
     67   [MII_LBRERROR   ] = "MII_LBRERROR",
     68   [MII_PHYADDR    ] = "MII_PHYADDR",
     69   [MII_RESV2      ] = "MII_RESV2",
     70   [MII_TPISTATUS  ] = "MII_TPISTATUS",
     71   [MII_NCONFIG    ] = "MII_NCONFIG",
     72 };
     73 #define mmr_name(off) (reg_names[off] ? : "<INV>")
     74 #define mmr_off reg_off
     75 
     76 static unsigned
     77 eth_phy_io_write_buffer (struct hw *me, const void *source,
     78 			 int space, address_word addr, unsigned nr_bytes)
     79 {
     80   struct eth_phy *phy = hw_data (me);
     81   bu16 reg_off;
     82   bu16 value;
     83   bu16 *valuep;
     84 
     85   value = dv_load_2 (source);
     86 
     87   reg_off = addr - phy->base;
     88   valuep = (void *)((unsigned long)phy + reg_base() + reg_off);
     89 
     90   HW_TRACE_WRITE ();
     91 
     92   switch (reg_off)
     93     {
     94     case MII_BMCR:
     95       *valuep = value;
     96       break;
     97     case MII_PHYSID1:
     98     case MII_PHYSID2:
     99       /* Discard writes to these.  */
    100       break;
    101     default:
    102       /* XXX: Discard writes to unknown regs ?  */
    103       *valuep = value;
    104       break;
    105     }
    106 
    107   return nr_bytes;
    108 }
    109 
    110 static unsigned
    111 eth_phy_io_read_buffer (struct hw *me, void *dest,
    112 			int space, address_word addr, unsigned nr_bytes)
    113 {
    114   struct eth_phy *phy = hw_data (me);
    115   bu16 reg_off;
    116   bu16 *valuep;
    117 
    118   reg_off = addr - phy->base;
    119   valuep = (void *)((unsigned long)phy + reg_base() + reg_off);
    120 
    121   HW_TRACE_READ ();
    122 
    123   switch (reg_off)
    124     {
    125     case MII_BMCR:
    126       dv_store_2 (dest, *valuep);
    127       break;
    128     case MII_BMSR:
    129       /* XXX: Let people control this ?  */
    130       *valuep = BMSR_100FULL | BMSR_100HALF | BMSR_10FULL | BMSR_10HALF |
    131 		BMSR_ANEGCOMPLETE | BMSR_ANEGCAPABLE | BMSR_LSTATUS;
    132       dv_store_2 (dest, *valuep);
    133       break;
    134     case MII_LPA:
    135       /* XXX: Let people control this ?  */
    136       *valuep = LPA_100FULL | LPA_100HALF | LPA_10FULL | LPA_10HALF;
    137       dv_store_2 (dest, *valuep);
    138       break;
    139     default:
    140       dv_store_2 (dest, *valuep);
    141       break;
    142     }
    143 
    144   return nr_bytes;
    145 }
    146 
    147 static void
    148 attach_eth_phy_regs (struct hw *me, struct eth_phy *phy)
    149 {
    150   address_word attach_address;
    151   int attach_space;
    152   unsigned attach_size;
    153   reg_property_spec reg;
    154 
    155   if (hw_find_property (me, "reg") == NULL)
    156     hw_abort (me, "Missing \"reg\" property");
    157 
    158   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
    159     hw_abort (me, "\"reg\" property must contain three addr/size entries");
    160 
    161   hw_unit_address_to_attach_address (hw_parent (me),
    162 				     &reg.address,
    163 				     &attach_space, &attach_address, me);
    164   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
    165 
    166   if (attach_size != REG_PHY_SIZE)
    167     hw_abort (me, "\"reg\" size must be %#x", REG_PHY_SIZE);
    168 
    169   hw_attach_address (hw_parent (me),
    170 		     0, attach_space, attach_address, attach_size, me);
    171 
    172   phy->base = attach_address;
    173 }
    174 
    175 static void
    176 eth_phy_finish (struct hw *me)
    177 {
    178   struct eth_phy *phy;
    179 
    180   phy = HW_ZALLOC (me, struct eth_phy);
    181 
    182   set_hw_data (me, phy);
    183   set_hw_io_read_buffer (me, eth_phy_io_read_buffer);
    184   set_hw_io_write_buffer (me, eth_phy_io_write_buffer);
    185 
    186   attach_eth_phy_regs (me, phy);
    187 
    188   /* Initialize the PHY.  */
    189   phy->regs[MII_PHYSID1] = 0;    /* Unassigned Vendor */
    190   phy->regs[MII_PHYSID2] = 0xAD; /* Product */
    191 }
    192 
    193 #else
    194 
    195 static void
    196 eth_phy_finish (struct hw *me)
    197 {
    198   HW_TRACE ((me, "No linux/mii.h support found"));
    199 }
    200 
    201 #endif
    202 
    203 const struct hw_descriptor dv_eth_phy_descriptor[] =
    204 {
    205   {"eth_phy", eth_phy_finish,},
    206   {NULL, NULL},
    207 };
    208