196136Sobrien/* Ethernet Physical Receiver model. 2150234Skan 3150234Skan Copyright (C) 2010-2023 Free Software Foundation, Inc. 4150234Skan Contributed by Analog Devices, Inc. 596340Sobrien 6132751Skan This file is part of simulators. 7132751Skan 896340Sobrien This program is free software; you can redistribute it and/or modify 9132751Skan it under the terms of the GNU General Public License as published by 1096340Sobrien the Free Software Foundation; either version 3 of the License, or 1196340Sobrien (at your option) any later version. 12132751Skan 1396340Sobrien This program is distributed in the hope that it will be useful, 1496340Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 15132751Skan MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1696340Sobrien GNU General Public License for more details. 1796340Sobrien 18132751Skan You should have received a copy of the GNU General Public License 1996340Sobrien along with this program. If not, see <http://www.gnu.org/licenses/>. */ 2096340Sobrien 21132751Skan/* This must come before any other includes. */ 2296340Sobrien#include "defs.h" 2396340Sobrien 24132751Skan#include "sim-main.h" 25246857Sdim#include "devices.h" 2696340Sobrien 27132751Skan#if defined (HAVE_LINUX_MII_H) && defined (HAVE_LINUX_TYPES_H) 2896340Sobrien 2996340Sobrien/* Workaround old/broken linux headers. */ 30132751Skan#include <linux/types.h> 3196340Sobrien#include <linux/mii.h> 3296340Sobrien 33132751Skan#define REG_PHY_SIZE 0x20 3496340Sobrien 3596340Sobrienstruct eth_phy 36132751Skan{ 37140864Skan bu32 base; 3896340Sobrien bu16 regs[REG_PHY_SIZE]; 39169718Skan}; 40169718Skan#define reg_base() offsetof(struct eth_phy, regs[0]) 41169718Skan#define reg_offset(reg) (offsetof(struct eth_phy, reg) - reg_base()) 42132751Skan#define reg_idx(reg) (reg_offset (reg) / 4) 4396340Sobrien 4496340Sobrienstatic const char * const reg_names[] = 45132751Skan{ 4696340Sobrien [MII_BMCR ] = "MII_BMCR", 4796340Sobrien [MII_BMSR ] = "MII_BMSR", 48132751Skan [MII_PHYSID1 ] = "MII_PHYSID1", 49132751Skan [MII_PHYSID2 ] = "MII_PHYSID2", 5096340Sobrien [MII_ADVERTISE ] = "MII_ADVERTISE", 51132751Skan [MII_LPA ] = "MII_LPA", 5296340Sobrien [MII_EXPANSION ] = "MII_EXPANSION", 5396340Sobrien#ifdef MII_CTRL1000 54132751Skan [MII_CTRL1000 ] = "MII_CTRL1000", 5596340Sobrien#endif 5696340Sobrien#ifdef MII_STAT1000 57132751Skan [MII_STAT1000 ] = "MII_STAT1000", 5896340Sobrien#endif 5996340Sobrien#ifdef MII_ESTATUS 60132751Skan [MII_ESTATUS ] = "MII_ESTATUS", 6196340Sobrien#endif 6296340Sobrien [MII_DCOUNTER ] = "MII_DCOUNTER", 63132751Skan [MII_FCSCOUNTER ] = "MII_FCSCOUNTER", 64132751Skan [MII_NWAYTEST ] = "MII_NWAYTEST", 6596340Sobrien [MII_RERRCOUNTER] = "MII_RERRCOUNTER", 66132751Skan [MII_SREVISION ] = "MII_SREVISION", 6796340Sobrien [MII_RESV1 ] = "MII_RESV1", 6896340Sobrien [MII_LBRERROR ] = "MII_LBRERROR", 69132751Skan [MII_PHYADDR ] = "MII_PHYADDR", 70246857Sdim [MII_RESV2 ] = "MII_RESV2", 7196340Sobrien [MII_TPISTATUS ] = "MII_TPISTATUS", 72132751Skan [MII_NCONFIG ] = "MII_NCONFIG", 7396340Sobrien}; 7496340Sobrien#define mmr_name(off) (reg_names[off] ? : "<INV>") 75132751Skan#define mmr_off reg_off 76132751Skan 7796340Sobrienstatic unsigned 78169718Skaneth_phy_io_write_buffer (struct hw *me, const void *source, 79169718Skan int space, address_word addr, unsigned nr_bytes) 8096340Sobrien{ 81132751Skan struct eth_phy *phy = hw_data (me); 8296340Sobrien bu16 reg_off; 8396340Sobrien bu16 value; 84132751Skan bu16 *valuep; 8596340Sobrien 8696340Sobrien value = dv_load_2 (source); 87132751Skan 8896340Sobrien reg_off = addr - phy->base; 8996340Sobrien valuep = (void *)((uintptr_t)phy + reg_base() + reg_off); 90132751Skan 91132751Skan HW_TRACE_WRITE (); 92132751Skan 93132751Skan switch (reg_off) 9496340Sobrien { 9596340Sobrien case MII_BMCR: 96132751Skan *valuep = value; 97140861Skan break; 9896340Sobrien case MII_PHYSID1: 99132751Skan case MII_PHYSID2: 10096340Sobrien /* Discard writes to these. */ 10196340Sobrien break; 102132751Skan default: 103246857Sdim /* XXX: Discard writes to unknown regs ? */ 10496340Sobrien *valuep = value; 105132751Skan break; 10696340Sobrien } 10796340Sobrien 108132751Skan return nr_bytes; 109132751Skan} 110132751Skan 111132751Skanstatic unsigned 11296340Sobrieneth_phy_io_read_buffer (struct hw *me, void *dest, 11396340Sobrien int space, address_word addr, unsigned nr_bytes) 114132751Skan{ 115144140Sdas struct eth_phy *phy = hw_data (me); 11696340Sobrien bu16 reg_off; 117132751Skan bu16 *valuep; 118132751Skan 119132751Skan reg_off = addr - phy->base; 120169718Skan valuep = (void *)((uintptr_t)phy + reg_base() + reg_off); 121169718Skan 122169718Skan HW_TRACE_READ (); 123132751Skan 12496340Sobrien switch (reg_off) 12596340Sobrien { 126169718Skan case MII_BMCR: 127169718Skan dv_store_2 (dest, *valuep); 128169718Skan break; 12996340Sobrien case MII_BMSR: 130132751Skan /* XXX: Let people control this ? */ 13196340Sobrien *valuep = BMSR_100FULL | BMSR_100HALF | BMSR_10FULL | BMSR_10HALF | 13296340Sobrien BMSR_ANEGCOMPLETE | BMSR_ANEGCAPABLE | BMSR_LSTATUS; 133132751Skan dv_store_2 (dest, *valuep); 13496340Sobrien break; 13596340Sobrien case MII_LPA: 136132751Skan /* XXX: Let people control this ? */ 137246857Sdim *valuep = LPA_100FULL | LPA_100HALF | LPA_10FULL | LPA_10HALF; 13896340Sobrien dv_store_2 (dest, *valuep); 139132751Skan break; 140169718Skan default: 14196340Sobrien dv_store_2 (dest, *valuep); 142132751Skan break; 143169718Skan } 14496340Sobrien 145132751Skan return nr_bytes; 146169718Skan} 14796340Sobrien 148132751Skanstatic void 149132751Skanattach_eth_phy_regs (struct hw *me, struct eth_phy *phy) 150111116Skan{ 151169718Skan address_word attach_address; 152169718Skan int attach_space; 153169718Skan unsigned attach_size; 154132751Skan reg_property_spec reg; 155132751Skan 156132751Skan if (hw_find_property (me, "reg") == NULL) 157132751Skan hw_abort (me, "Missing \"reg\" property"); 15896340Sobrien 15996340Sobrien if (!hw_find_reg_array_property (me, "reg", 0, ®)) 160132751Skan hw_abort (me, "\"reg\" property must contain three addr/size entries"); 16196340Sobrien 16296340Sobrien hw_unit_address_to_attach_address (hw_parent (me), 163132751Skan ®.address, 16496340Sobrien &attach_space, &attach_address, me); 16596340Sobrien hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); 166132751Skan 16796340Sobrien if (attach_size != REG_PHY_SIZE) 16896340Sobrien hw_abort (me, "\"reg\" size must be %#x", REG_PHY_SIZE); 169132751Skan 17096340Sobrien hw_attach_address (hw_parent (me), 17196340Sobrien 0, attach_space, attach_address, attach_size, me); 172132751Skan 17396340Sobrien phy->base = attach_address; 17496340Sobrien} 175169718Skan 176132751Skanstatic void 177132751Skaneth_phy_finish (struct hw *me) 178169718Skan{ 179169718Skan struct eth_phy *phy; 180169718Skan 181132751Skan phy = HW_ZALLOC (me, struct eth_phy); 18296340Sobrien 18396340Sobrien set_hw_data (me, phy); 184132751Skan set_hw_io_read_buffer (me, eth_phy_io_read_buffer); 185144140Sdas set_hw_io_write_buffer (me, eth_phy_io_write_buffer); 18696340Sobrien 187132751Skan attach_eth_phy_regs (me, phy); 188132751Skan 189132751Skan /* Initialize the PHY. */ 190132751Skan phy->regs[MII_PHYSID1] = 0; /* Unassigned Vendor */ 191132751Skan phy->regs[MII_PHYSID2] = 0xAD; /* Product */ 192132751Skan} 193162553Skan 194162553Skan#else 195162553Skan 196162553Skanstatic void 197162553Skaneth_phy_finish (struct hw *me) 198162553Skan{ 199162553Skan HW_TRACE ((me, "No linux/mii.h support found")); 200162553Skan} 201162553Skan 202162553Skan#endif 203162553Skan 204162553Skanconst struct hw_descriptor dv_eth_phy_descriptor[] = 205162553Skan{ 206162553Skan {"eth_phy", eth_phy_finish,}, 207162553Skan {NULL, NULL}, 208132751Skan}; 209132751Skan