1 1.1 christos /* Ethernet Physical Receiver model. 2 1.1 christos 3 1.11 christos Copyright (C) 2010-2024 Free Software Foundation, Inc. 4 1.1 christos Contributed by Analog Devices, Inc. 5 1.1 christos 6 1.1 christos This file is part of simulators. 7 1.1 christos 8 1.1 christos This program is free software; you can redistribute it and/or modify 9 1.1 christos it under the terms of the GNU General Public License as published by 10 1.1 christos the Free Software Foundation; either version 3 of the License, or 11 1.1 christos (at your option) any later version. 12 1.1 christos 13 1.1 christos This program is distributed in the hope that it will be useful, 14 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 15 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 1.1 christos GNU General Public License for more details. 17 1.1 christos 18 1.1 christos You should have received a copy of the GNU General Public License 19 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 20 1.1 christos 21 1.10 christos /* This must come before any other includes. */ 22 1.10 christos #include "defs.h" 23 1.1 christos 24 1.1 christos #include "sim-main.h" 25 1.1 christos #include "devices.h" 26 1.1 christos 27 1.1 christos #if defined (HAVE_LINUX_MII_H) && defined (HAVE_LINUX_TYPES_H) 28 1.1 christos 29 1.1 christos /* Workaround old/broken linux headers. */ 30 1.1 christos #include <linux/types.h> 31 1.1 christos #include <linux/mii.h> 32 1.1 christos 33 1.1 christos #define REG_PHY_SIZE 0x20 34 1.1 christos 35 1.1 christos struct eth_phy 36 1.1 christos { 37 1.1 christos bu32 base; 38 1.1 christos bu16 regs[REG_PHY_SIZE]; 39 1.1 christos }; 40 1.1 christos #define reg_base() offsetof(struct eth_phy, regs[0]) 41 1.1 christos #define reg_offset(reg) (offsetof(struct eth_phy, reg) - reg_base()) 42 1.1 christos #define reg_idx(reg) (reg_offset (reg) / 4) 43 1.1 christos 44 1.1 christos static const char * const reg_names[] = 45 1.1 christos { 46 1.1 christos [MII_BMCR ] = "MII_BMCR", 47 1.1 christos [MII_BMSR ] = "MII_BMSR", 48 1.1 christos [MII_PHYSID1 ] = "MII_PHYSID1", 49 1.1 christos [MII_PHYSID2 ] = "MII_PHYSID2", 50 1.1 christos [MII_ADVERTISE ] = "MII_ADVERTISE", 51 1.1 christos [MII_LPA ] = "MII_LPA", 52 1.1 christos [MII_EXPANSION ] = "MII_EXPANSION", 53 1.1 christos #ifdef MII_CTRL1000 54 1.1 christos [MII_CTRL1000 ] = "MII_CTRL1000", 55 1.1 christos #endif 56 1.1 christos #ifdef MII_STAT1000 57 1.1 christos [MII_STAT1000 ] = "MII_STAT1000", 58 1.1 christos #endif 59 1.1 christos #ifdef MII_ESTATUS 60 1.1 christos [MII_ESTATUS ] = "MII_ESTATUS", 61 1.1 christos #endif 62 1.1 christos [MII_DCOUNTER ] = "MII_DCOUNTER", 63 1.1 christos [MII_FCSCOUNTER ] = "MII_FCSCOUNTER", 64 1.1 christos [MII_NWAYTEST ] = "MII_NWAYTEST", 65 1.1 christos [MII_RERRCOUNTER] = "MII_RERRCOUNTER", 66 1.1 christos [MII_SREVISION ] = "MII_SREVISION", 67 1.1 christos [MII_RESV1 ] = "MII_RESV1", 68 1.1 christos [MII_LBRERROR ] = "MII_LBRERROR", 69 1.1 christos [MII_PHYADDR ] = "MII_PHYADDR", 70 1.1 christos [MII_RESV2 ] = "MII_RESV2", 71 1.1 christos [MII_TPISTATUS ] = "MII_TPISTATUS", 72 1.1 christos [MII_NCONFIG ] = "MII_NCONFIG", 73 1.1 christos }; 74 1.1 christos #define mmr_name(off) (reg_names[off] ? : "<INV>") 75 1.1 christos #define mmr_off reg_off 76 1.1 christos 77 1.1 christos static unsigned 78 1.1 christos eth_phy_io_write_buffer (struct hw *me, const void *source, 79 1.1 christos int space, address_word addr, unsigned nr_bytes) 80 1.1 christos { 81 1.1 christos struct eth_phy *phy = hw_data (me); 82 1.1 christos bu16 reg_off; 83 1.1 christos bu16 value; 84 1.1 christos bu16 *valuep; 85 1.1 christos 86 1.1 christos value = dv_load_2 (source); 87 1.1 christos 88 1.1 christos reg_off = addr - phy->base; 89 1.10 christos valuep = (void *)((uintptr_t)phy + reg_base() + reg_off); 90 1.1 christos 91 1.1 christos HW_TRACE_WRITE (); 92 1.1 christos 93 1.1 christos switch (reg_off) 94 1.1 christos { 95 1.1 christos case MII_BMCR: 96 1.1 christos *valuep = value; 97 1.1 christos break; 98 1.1 christos case MII_PHYSID1: 99 1.1 christos case MII_PHYSID2: 100 1.1 christos /* Discard writes to these. */ 101 1.1 christos break; 102 1.1 christos default: 103 1.1 christos /* XXX: Discard writes to unknown regs ? */ 104 1.1 christos *valuep = value; 105 1.1 christos break; 106 1.1 christos } 107 1.1 christos 108 1.1 christos return nr_bytes; 109 1.1 christos } 110 1.1 christos 111 1.1 christos static unsigned 112 1.1 christos eth_phy_io_read_buffer (struct hw *me, void *dest, 113 1.1 christos int space, address_word addr, unsigned nr_bytes) 114 1.1 christos { 115 1.1 christos struct eth_phy *phy = hw_data (me); 116 1.1 christos bu16 reg_off; 117 1.1 christos bu16 *valuep; 118 1.1 christos 119 1.1 christos reg_off = addr - phy->base; 120 1.10 christos valuep = (void *)((uintptr_t)phy + reg_base() + reg_off); 121 1.1 christos 122 1.1 christos HW_TRACE_READ (); 123 1.1 christos 124 1.1 christos switch (reg_off) 125 1.1 christos { 126 1.1 christos case MII_BMCR: 127 1.1 christos dv_store_2 (dest, *valuep); 128 1.1 christos break; 129 1.1 christos case MII_BMSR: 130 1.1 christos /* XXX: Let people control this ? */ 131 1.1 christos *valuep = BMSR_100FULL | BMSR_100HALF | BMSR_10FULL | BMSR_10HALF | 132 1.1 christos BMSR_ANEGCOMPLETE | BMSR_ANEGCAPABLE | BMSR_LSTATUS; 133 1.1 christos dv_store_2 (dest, *valuep); 134 1.1 christos break; 135 1.1 christos case MII_LPA: 136 1.1 christos /* XXX: Let people control this ? */ 137 1.1 christos *valuep = LPA_100FULL | LPA_100HALF | LPA_10FULL | LPA_10HALF; 138 1.1 christos dv_store_2 (dest, *valuep); 139 1.1 christos break; 140 1.1 christos default: 141 1.1 christos dv_store_2 (dest, *valuep); 142 1.1 christos break; 143 1.1 christos } 144 1.1 christos 145 1.1 christos return nr_bytes; 146 1.1 christos } 147 1.1 christos 148 1.1 christos static void 149 1.1 christos attach_eth_phy_regs (struct hw *me, struct eth_phy *phy) 150 1.1 christos { 151 1.1 christos address_word attach_address; 152 1.1 christos int attach_space; 153 1.1 christos unsigned attach_size; 154 1.1 christos reg_property_spec reg; 155 1.1 christos 156 1.1 christos if (hw_find_property (me, "reg") == NULL) 157 1.1 christos hw_abort (me, "Missing \"reg\" property"); 158 1.1 christos 159 1.1 christos if (!hw_find_reg_array_property (me, "reg", 0, ®)) 160 1.1 christos hw_abort (me, "\"reg\" property must contain three addr/size entries"); 161 1.1 christos 162 1.1 christos hw_unit_address_to_attach_address (hw_parent (me), 163 1.1 christos ®.address, 164 1.1 christos &attach_space, &attach_address, me); 165 1.1 christos hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); 166 1.1 christos 167 1.1 christos if (attach_size != REG_PHY_SIZE) 168 1.1 christos hw_abort (me, "\"reg\" size must be %#x", REG_PHY_SIZE); 169 1.1 christos 170 1.1 christos hw_attach_address (hw_parent (me), 171 1.1 christos 0, attach_space, attach_address, attach_size, me); 172 1.1 christos 173 1.1 christos phy->base = attach_address; 174 1.1 christos } 175 1.1 christos 176 1.1 christos static void 177 1.1 christos eth_phy_finish (struct hw *me) 178 1.1 christos { 179 1.1 christos struct eth_phy *phy; 180 1.1 christos 181 1.1 christos phy = HW_ZALLOC (me, struct eth_phy); 182 1.1 christos 183 1.1 christos set_hw_data (me, phy); 184 1.1 christos set_hw_io_read_buffer (me, eth_phy_io_read_buffer); 185 1.1 christos set_hw_io_write_buffer (me, eth_phy_io_write_buffer); 186 1.1 christos 187 1.1 christos attach_eth_phy_regs (me, phy); 188 1.1 christos 189 1.1 christos /* Initialize the PHY. */ 190 1.1 christos phy->regs[MII_PHYSID1] = 0; /* Unassigned Vendor */ 191 1.1 christos phy->regs[MII_PHYSID2] = 0xAD; /* Product */ 192 1.1 christos } 193 1.1 christos 194 1.1 christos #else 195 1.1 christos 196 1.1 christos static void 197 1.1 christos eth_phy_finish (struct hw *me) 198 1.1 christos { 199 1.1 christos HW_TRACE ((me, "No linux/mii.h support found")); 200 1.1 christos } 201 1.1 christos 202 1.1 christos #endif 203 1.1 christos 204 1.1 christos const struct hw_descriptor dv_eth_phy_descriptor[] = 205 1.1 christos { 206 1.1 christos {"eth_phy", eth_phy_finish,}, 207 1.1 christos {NULL, NULL}, 208 1.1 christos }; 209